//****************************************************************************************************** // SerializableMeasurement.cs - Gbtc // // Copyright © 2010, 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 Eclipse Public License -v 1.0 (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/eclipse-1.0.php // // 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: // ---------------------------------------------------------------------------------------------------- // 08/23/2010 - J. Ritchie Carroll // Generated original version of source code. // 06/07/2011 - J. Ritchie Carroll // Implemented binary image bug fix as found and proposed by Luc Cezard. // //****************************************************************************************************** using GSF.Parsing; using System; using System.Text; namespace GSF.TimeSeries.Transport { /// /// Represents a that can be serialized. /// /// /// This measurement implementation is serialized through /// to allow complete control of binary format. All measurement properties are serialized /// at their full resolution and no attempt is made to optimize the binary image for /// purposes of size reduction. /// public class SerializableMeasurement : Measurement, ISupportBinaryImage { #region [ Members ] // Constants /// /// Fixed byte length of a . /// public const int FixedLength = 64; // Fields private Encoding m_encoding; #endregion #region [ Constructors ] /// /// Creates a new . /// /// Character encoding used to convert strings to binary. public SerializableMeasurement(Encoding encoding) { if ((object)encoding == null) throw new ArgumentNullException("encoding", "Cannot create serializable measurement with no encoding."); m_encoding = encoding; } /// /// Creates a new from an existing value. /// /// Source value. /// Character encoding used to convert strings to binary. public SerializableMeasurement(IMeasurement measurement, Encoding encoding) : this(encoding) { ID = measurement.ID; Key = measurement.Key; Value = measurement.Value; Adder = measurement.Adder; Multiplier = measurement.Multiplier; Timestamp = measurement.Timestamp; StateFlags = measurement.StateFlags; } #endregion #region [ Properties ] /// /// Gets the length of the . /// public int BinaryLength { get { int sourceLength = m_encoding.GetByteCount(Key.Source.ToNonNullString()); int tagLength = m_encoding.GetByteCount(TagName.ToNonNullString()); return FixedLength + sourceLength + tagLength; } } #endregion #region [ Methods ] /// /// Initializes from the specified binary image. /// /// Buffer containing binary image to parse. /// 0-based starting index in the to start parsing. /// Valid number of bytes within from . /// The number of bytes used for initialization in the (i.e., the number of bytes parsed). /// Not enough buffer available to deserialize measurement. /// is null. /// /// or is less than 0 -or- /// and will exceed length. /// public int ParseBinaryImage(byte[] buffer, int startIndex, int length) { buffer.ValidateParameters(startIndex, length); if (length < FixedLength) throw new InvalidOperationException("Not enough buffer available to deserialize measurement"); int size, index = startIndex; uint keyID; string keySource = ""; // Decode key ID keyID = EndianOrder.BigEndian.ToUInt32(buffer, index); index += 4; // Decode key source string length size = EndianOrder.BigEndian.ToInt32(buffer, index); index += 4; // Decode key source string if (size > 0) { keySource = m_encoding.GetString(buffer, index, size); index += size; } // Decode signal ID ID = EndianOrder.BigEndian.ToGuid(buffer, index); index += 16; // Apply parsed key changes Key = new MeasurementKey(ID, keyID, keySource); // Decode tag name string length size = EndianOrder.BigEndian.ToInt32(buffer, index); index += 4; // Decode tag name string if (size > 0) { TagName = m_encoding.GetString(buffer, index, size); index += size; } else TagName = null; // Decode value Value = EndianOrder.BigEndian.ToDouble(buffer, index); index += 8; // Decode adder Adder = EndianOrder.BigEndian.ToDouble(buffer, index); index += 8; // Decode multiplier Multiplier = EndianOrder.BigEndian.ToDouble(buffer, index); index += 8; // Decode timestamp Timestamp = EndianOrder.BigEndian.ToInt64(buffer, index); index += 8; // Decode state flags StateFlags = (MeasurementStateFlags)EndianOrder.BigEndian.ToUInt32(buffer, index); index += 4; return (index - startIndex); } /// /// 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. /// /// /// /// Field: Bytes:
/// --------- ---------
/// Key ID 4
/// SourceLen 4
/// Source SourceLen
/// Signal ID 16
/// TagLen 4
/// Tag TagLen
/// Value 8
/// Adder 8
/// Multipler 8
/// Ticks 8
/// Flags 4
///
/// /// Constant Length = 64
/// Variable Length = SourceLen + TagLen ///
///
public int GenerateBinaryImage(byte[] buffer, int startIndex) { int length = BinaryLength; buffer.ValidateParameters(startIndex, length); byte[] bytes; int size, index = startIndex; string source = Key.Source.ToNonNullString(); string tagName = TagName.ToNonNullString(); // Encode key ID EndianOrder.BigEndian.CopyBytes(Key.ID, buffer, index); index += 4; // Encode key source string length bytes = m_encoding.GetBytes(source); size = bytes.Length; EndianOrder.BigEndian.CopyBytes(size, buffer, index); index += 4; // Encode key source string if (size > 0) { Buffer.BlockCopy(bytes, 0, buffer, index, size); index += size; } // Encode signal ID EndianOrder.BigEndian.CopyBytes(ID, buffer, index); index += 16; // Encode tag name string length bytes = m_encoding.GetBytes(tagName); size = bytes.Length; EndianOrder.BigEndian.CopyBytes(size, buffer, index); index += 4; // Encode tag name string if (size > 0) { Buffer.BlockCopy(bytes, 0, buffer, index, size); index += size; } // Encode value EndianOrder.BigEndian.CopyBytes(Value, buffer, index); index += 8; // Encode adder EndianOrder.BigEndian.CopyBytes(Adder, buffer, index); index += 8; // Encode multiplier EndianOrder.BigEndian.CopyBytes(Multiplier, buffer, index); index += 8; // Encode timestamp EndianOrder.BigEndian.CopyBytes((long)Timestamp, buffer, index); index += 8; // Encode state flags EndianOrder.BigEndian.CopyBytes((uint)StateFlags, buffer, index); return length; } #endregion } }