//******************************************************************************************************
// 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
}
}