//****************************************************************************************************** // StateRecord.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: // ---------------------------------------------------------------------------------------------------- // 03/08/2007 - Pinal C. Patel // Generated original version of code based on DatAWare system specifications by Brian B. Fox, GSF. // 03/31/2008 - Pinal C. Patel // Removed Obsolete tag from ActiveDataBlockIndex and ActiveDataBlockSlot as it's being used. // 04/20/2009 - Pinal C. Patel // Converted to C#. // 09/15/2009 - Stephen C. Wills // Added new header and license agreement. // 12/01/2009 - Pinal C. Patel // Modified ActiveDataBlockIndex to default to -1 for values that are less than 0. // 10/11/2010 - Mihir Brahmbhatt // Updated header and license agreement. // 11/30/2011 - J. Ritchie Carroll // Modified to support buffer optimized ISupportBinaryImage. // 12/14/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using GSF.Parsing; namespace GSF.Historian.Files { /// /// Represents a record in the that contains the state information associated to a . /// /// /// /// public class StateRecord : ISupportBinaryImage, IComparable { // ************************************************************************************************** // * Binary Structure * // ************************************************************************************************** // * # Of Bytes Byte Index Data Type Property Name * // * ---------- ---------- ---------- --------------------------------------------------------------* // * 16 0-15 Byte(16) ArchivedData * // * 16 16-31 Byte(16) PreviousData * // * 16 32-47 Byte(16) CurrentData * // * 4 48-51 Int32 ActiveDataBlockIndex * // * 4 52-55 Int32 ActiveDataBlockSlot * // * 8 56-63 Double Slope1 * // * 8 64-71 Double Slope2 * // ************************************************************************************************** #region [ Members ] // Constants /// /// Specifies the number of bytes in the binary image of . /// public const int FixedLength = 72; // Fields private readonly int m_historianID; private StateRecordDataPoint m_archivedData; private StateRecordDataPoint m_previousData; private StateRecordDataPoint m_currentData; private int m_activeDataBlockIndex; private int m_activeDataBlockSlot; private double m_slope1; private double m_slope2; #endregion #region [ Constructors ] /// /// Initializes a new instance of the class. /// /// Historian identifier of . public StateRecord(int historianID) { m_historianID = historianID; m_archivedData = new StateRecordDataPoint(m_historianID); m_previousData = new StateRecordDataPoint(m_historianID); m_currentData = new StateRecordDataPoint(m_historianID); m_activeDataBlockIndex = -1; m_activeDataBlockSlot = 1; } /// /// Initializes a new instance of the class. /// /// Historian identifier of . /// Binary image to be used for initializing . /// 0-based starting index of initialization data in the . /// Valid number of bytes in from . public StateRecord(int historianID, byte[] buffer, int startIndex, int length) : this(historianID) { ParseBinaryImage(buffer, startIndex, length); } #endregion #region [ Properties ] /// /// Gets or sets the most recently archived for the . /// /// The value being assigned is null. public StateRecordDataPoint ArchivedData { get { return m_archivedData; } set { if ((object)value == null) throw new ArgumentNullException(nameof(value)); m_archivedData = value; } } /// /// Gets or sets the previous received for the . /// /// The value being assigned is null. public StateRecordDataPoint PreviousData { get { return m_previousData; } set { if ((object)value == null) throw new ArgumentNullException(nameof(value)); m_previousData = value; } } /// /// Gets or sets the most current received for the . /// /// The value being assigned is null. public StateRecordDataPoint CurrentData { get { return m_currentData; } set { if ((object)value == null) throw new ArgumentNullException(nameof(value)); m_currentData = value; } } /// /// Gets or sets the 0-based index of the active for the . /// /// Index is persisted to disk as 1-based index for backwards compatibility. public int ActiveDataBlockIndex { get { if (m_activeDataBlockIndex < 0) return m_activeDataBlockIndex; else return m_activeDataBlockIndex - 1; } set { if (value < 0) m_activeDataBlockIndex = -1; else m_activeDataBlockIndex = value + 1; } } /// /// Gets or sets the next slot position in the active for the where data can be written. /// public int ActiveDataBlockSlot { get { return m_activeDataBlockSlot; } set { if (value <= 0) m_activeDataBlockSlot = 1; else m_activeDataBlockSlot = value; } } /// /// Gets or sets slope #1 used in the piece-wise linear compression of data. /// public double Slope1 { get { return m_slope1; } set { m_slope1 = value; } } /// /// Gets or sets slope #2 used in the piece-wise linear compression of data. /// public double Slope2 { get { return m_slope2; } set { m_slope2 = value; } } /// /// Gets the historian identifier of . /// public int HistorianID { get { return m_historianID; } } /// /// Gets the object for . /// public StateRecordSummary Summary { get { return new StateRecordSummary(this); } } /// /// Gets the length of the . /// public int BinaryLength { get { return FixedLength; } } #endregion #region [ Methods ] /// /// Initializes from the specified . /// /// Binary image to be used for initializing . /// 0-based starting index of initialization data in the . /// Valid number of bytes in from . /// Number of bytes used from the for initializing . public int ParseBinaryImage(byte[] buffer, int startIndex, int length) { if (length >= FixedLength) { // Binary image has sufficient data. m_archivedData.ParseBinaryImage(buffer, startIndex, length); m_previousData.ParseBinaryImage(buffer, startIndex + 16, length - 16); m_currentData.ParseBinaryImage(buffer, startIndex + 32, length - 32); ActiveDataBlockIndex = LittleEndian.ToInt32(buffer, startIndex + 48) - 1; ActiveDataBlockSlot = LittleEndian.ToInt32(buffer, startIndex + 52); Slope1 = LittleEndian.ToDouble(buffer, startIndex + 56); Slope2 = LittleEndian.ToDouble(buffer, startIndex + 64); return FixedLength; } else { // Binary image does not have sufficient data. return 0; } } /// /// Generates binary image of the and copies it into the given buffer, for bytes. /// /// Buffer used to hold generated binary image of the source object. /// 0-based starting index in the to start writing. /// The number of bytes written to the . /// is null. /// /// or is less than 0 -or- /// and will exceed length. /// public int GenerateBinaryImage(byte[] buffer, int startIndex) { int length = BinaryLength; buffer.ValidateParameters(startIndex, length); m_archivedData.GenerateBinaryImage(buffer, startIndex); m_previousData.GenerateBinaryImage(buffer, startIndex + 16); m_currentData.GenerateBinaryImage(buffer, startIndex + 32); LittleEndian.CopyBytes(m_activeDataBlockIndex, buffer, startIndex + 48); LittleEndian.CopyBytes(m_activeDataBlockSlot, buffer, startIndex + 52); LittleEndian.CopyBytes(m_slope1, buffer, startIndex + 56); LittleEndian.CopyBytes(m_slope2, buffer, startIndex + 64); return length; } /// /// Compares the current object to . /// /// Object against which the current object is to be compared. /// /// Negative value if the current object is less than , /// Zero if the current object is equal to , /// Positive value if the current object is greater than . /// public virtual int CompareTo(object obj) { StateRecord other = obj as StateRecord; if (other == null) return 1; else return m_historianID.CompareTo(other.HistorianID); } /// /// Determines whether the current object is equal to . /// /// Object against which the current object is to be compared for equality. /// true if the current object is equal to ; otherwise false. public override bool Equals(object obj) { return (CompareTo(obj) == 0); } /// /// Returns the text representation of object. /// /// A value. public override string ToString() { return string.Format("ID={0}; ActiveDataBlock={1}", m_historianID, m_activeDataBlockIndex); } /// /// Returns the hash code for the current object. /// /// A 32-bit signed integer value. public override int GetHashCode() { return m_historianID.GetHashCode(); } #endregion } }