コード例 #1
0
        private void ProcessBinaryMeasurements(IEnumerable <ISupportBinaryImage> measurements, bool useCompactMeasurementFormat)
        {
            MemoryStream data = new MemoryStream();

            // Serialize data packet flags into response
            DataPacketFlags flags = DataPacketFlags.NoFlags; // No flags means bit is cleared, i.e., unsynchronized

            if (useCompactMeasurementFormat)
            {
                flags |= DataPacketFlags.Compact;
            }

            data.WriteByte((byte)flags);

            // No frame level timestamp is serialized into the data packet since all data is unsynchronized and essentially
            // published upon receipt, however timestamps are optionally included in the serialized measurements.

            // Serialize total number of measurement values to follow
            data.Write(EndianOrder.BigEndian.GetBytes(measurements.Count()), 0, 4);

            // Serialize measurements to data buffer
            foreach (ISupportBinaryImage measurement in measurements)
            {
                measurement.CopyBinaryImageToStream(data);
            }

            // Publish data packet to client
            if (m_parent != null)
            {
                m_parent.SendClientResponse(m_clientID, ServerResponse.DataPacket, ServerCommand.Subscribe, data.ToArray());
            }

            // Track last publication time
            m_lastPublishTime = DateTime.UtcNow.Ticks;
        }
コード例 #2
0
        private void ProcessBinaryMeasurements(IEnumerable <ISupportBinaryImage> measurements, long frameLevelTimestamp, bool useCompactMeasurementFormat)
        {
            MemoryStream data = new MemoryStream();

            // Serialize data packet flags into response
            DataPacketFlags flags = DataPacketFlags.Synchronized;

            if (useCompactMeasurementFormat)
            {
                flags |= DataPacketFlags.Compact;
            }

            data.WriteByte((byte)flags);

            // Serialize frame timestamp into data packet - this only occurs in synchronized data packets,
            // unsynchronized subcriptions always include timestamps in the serialized measurements
            data.Write(EndianOrder.BigEndian.GetBytes(frameLevelTimestamp), 0, 8);

            // Serialize total number of measurement values to follow
            data.Write(EndianOrder.BigEndian.GetBytes(measurements.Count()), 0, 4);

            // Serialize measurements to data buffer
            foreach (ISupportBinaryImage measurement in measurements)
            {
                measurement.CopyBinaryImageToStream(data);
            }

            // Publish data packet to client
            if (m_parent != null)
            {
                m_parent.SendClientResponse(m_clientID, ServerResponse.DataPacket, ServerCommand.Subscribe, data.ToArray());
            }
        }
コード例 #3
0
        private void ProcessBinaryMeasurements(IEnumerable <IBinaryMeasurement> measurements, long frameLevelTimestamp, bool useCompactMeasurementFormat, bool usePayloadCompression)
        {
            // Create working buffer
            using (BlockAllocatedMemoryStream workingBuffer = new BlockAllocatedMemoryStream())
            {
                // Serialize data packet flags into response
                DataPacketFlags flags = DataPacketFlags.Synchronized;

                if (useCompactMeasurementFormat)
                {
                    flags |= DataPacketFlags.Compact;
                }

                workingBuffer.WriteByte((byte)flags);

                // Serialize frame timestamp into data packet - this only occurs in synchronized data packets,
                // unsynchronized subscriptions always include timestamps in the serialized measurements
                workingBuffer.Write(BigEndian.GetBytes(frameLevelTimestamp), 0, 8);

                // Serialize total number of measurement values to follow
                workingBuffer.Write(BigEndian.GetBytes(measurements.Count()), 0, 4);

                if (usePayloadCompression && m_compressionModes.HasFlag(CompressionModes.TSSC))
                {
                    throw new InvalidOperationException("TSSC must be processed at the frame level. Please check call stack - this is considered an error.");
                }

                // Attempt compression when requested - encoding of compressed buffer only happens if size would be smaller than normal serialization
                if (!usePayloadCompression || !measurements.Cast <CompactMeasurement>().CompressPayload(workingBuffer, m_compressionStrength, false, ref flags))
                {
                    // Serialize measurements to data buffer
                    foreach (IBinaryMeasurement measurement in measurements)
                    {
                        measurement.CopyBinaryImageToStream(workingBuffer);
                    }
                }

                // Update data packet flags if it has updated compression flags
                if ((flags & DataPacketFlags.Compressed) > 0)
                {
                    workingBuffer.Seek(0, SeekOrigin.Begin);
                    workingBuffer.WriteByte((byte)flags);
                }

                // Publish data packet to client
                if ((object)m_parent != null)
                {
                    m_parent.SendClientResponse(m_clientID, ServerResponse.DataPacket, ServerCommand.Subscribe, workingBuffer.ToArray());
                }
            }
        }
コード例 #4
0
        private void ProcessBinaryMeasurements(IEnumerable <IBinaryMeasurement> measurements, bool useCompactMeasurementFormat, bool usePayloadCompression)
        {
            // Create working buffer
            using (BlockAllocatedMemoryStream workingBuffer = new BlockAllocatedMemoryStream())
            {
                // Serialize data packet flags into response
                DataPacketFlags flags = DataPacketFlags.NoFlags; // No flags means bit is cleared, i.e., unsynchronized

                if (useCompactMeasurementFormat)
                {
                    flags |= DataPacketFlags.Compact;
                }

                workingBuffer.WriteByte((byte)flags);

                // No frame level timestamp is serialized into the data packet since all data is unsynchronized and essentially
                // published upon receipt, however timestamps are optionally included in the serialized measurements.

                // Serialize total number of measurement values to follow
                workingBuffer.Write(BigEndian.GetBytes(measurements.Count()), 0, 4);

                // Attempt compression when requested - encoding of compressed buffer only happens if size would be smaller than normal serialization
                if (!usePayloadCompression || !measurements.Cast <CompactMeasurement>().CompressPayload(workingBuffer, m_compressionStrength, m_includeTime, ref flags))
                {
                    // Serialize measurements to data buffer
                    foreach (IBinaryMeasurement measurement in measurements)
                    {
                        measurement.CopyBinaryImageToStream(workingBuffer);
                    }
                }

                // Update data packet flags if it has updated compression flags
                if ((flags & DataPacketFlags.Compressed) > 0)
                {
                    workingBuffer.Seek(0, SeekOrigin.Begin);
                    workingBuffer.WriteByte((byte)flags);
                }

                // Publish data packet to client
                if ((object)m_parent != null)
                {
                    m_parent.SendClientResponse(m_clientID, ServerResponse.DataPacket, ServerCommand.Subscribe, workingBuffer.ToArray());
                }

                // Track last publication time
                m_lastPublishTime = DateTime.UtcNow.Ticks;
            }
        }
コード例 #5
0
        private void ProcessBinaryMeasurements(IEnumerable <IBinaryMeasurement> measurements, long frameLevelTimestamp, bool useCompactMeasurementFormat, bool usePayloadCompression)
        {
            // Reset working buffer
            m_workingBuffer.SetLength(0);

            // Serialize data packet flags into response
            DataPacketFlags flags = DataPacketFlags.Synchronized;

            if (useCompactMeasurementFormat)
            {
                flags |= DataPacketFlags.Compact;
            }

            m_workingBuffer.WriteByte((byte)flags);

            // Serialize frame timestamp into data packet - this only occurs in synchronized data packets,
            // unsynchronized subscriptions always include timestamps in the serialized measurements
            m_workingBuffer.Write(BigEndian.GetBytes(frameLevelTimestamp), 0, 8);

            // Serialize total number of measurement values to follow
            m_workingBuffer.Write(BigEndian.GetBytes(measurements.Count()), 0, 4);

            // Attempt compression when requested - encoding of compressed buffer only happens if size would be smaller than normal serialization
            if (!usePayloadCompression || !measurements.Cast <CompactMeasurement>().CompressPayload(m_workingBuffer, m_compressionStrength, false, ref flags))
            {
                // Serialize measurements to data buffer
                foreach (IBinaryMeasurement measurement in measurements)
                {
                    measurement.CopyBinaryImageToStream(m_workingBuffer);
                }
            }

            // Update data packet flags if it has updated compression flags
            if ((flags & DataPacketFlags.Compressed) > 0)
            {
                m_workingBuffer.Seek(0, SeekOrigin.Begin);
                m_workingBuffer.WriteByte((byte)flags);
            }

            // Publish data packet to client
            if ((object)m_parent != null)
            {
                m_parent.SendClientResponse(m_workingBuffer, m_clientID, ServerResponse.DataPacket, ServerCommand.Subscribe, m_workingBuffer.ToArray());
            }
        }
コード例 #6
0
ファイル: CompactMeasurement.cs プロジェクト: lyrain2009/gsf
        /// <summary>
        /// Decompresses <see cref="CompactMeasurement"/> values from the given <paramref name="source"/> buffer.
        /// </summary>
        /// <param name="source">Buffer with compressed <see cref="CompactMeasurement"/> payload.</param>
        /// <param name="signalIndexCache">Current <see cref="SignalIndexCache"/>.</param>
        /// <param name="index">Index into buffer where compressed payload begins.</param>
        /// <param name="dataLength">Length of all data within <paramref name="source"/> buffer.</param>
        /// <param name="measurementCount">Number of compressed measurements in the payload.</param>
        /// <param name="includeTime">Flag that determines if timestamps as included in the payload.</param>
        /// <param name="flags">Current <see cref="DataPacketFlags"/>.</param>
        /// <returns>Decompressed <see cref="CompactMeasurement"/> values from the given <paramref name="source"/> buffer.</returns>
        public static CompactMeasurement[] DecompressPayload(this byte[] source, SignalIndexCache signalIndexCache, int index, int dataLength, int measurementCount, bool includeTime, DataPacketFlags flags)
        {
            CompactMeasurement[] measurements = new CompactMeasurement[measurementCount];

            // Actual data length has to take into account response byte and in-response-to server command byte in the payload header
            //int dataLength = length - index - 2;
            int bufferLength = PatternDecompressor.MaximumSizeDecompressed(dataLength);

            // Copy source data into a decompression buffer
            byte[] buffer = new byte[bufferLength];
            Buffer.BlockCopy(source, index, buffer, 0, dataLength);

            // Check that OS endian-order matches endian-order of compressed data
            if (!(BitConverter.IsLittleEndian && (flags & DataPacketFlags.LittleEndianCompression) > 0))
            {
                // can be modified to decompress a payload that is in a non-native Endian order
                throw new NotImplementedException("Cannot currently decompress payload that is not in native endian-order.");
            }

            // Attempt to decompress buffer
            int uncompressedSize = PatternDecompressor.DecompressBuffer(buffer, 0, dataLength, bufferLength);

            if (uncompressedSize == 0)
            {
                throw new InvalidOperationException("Failed to decompress payload buffer - possible data corruption.");
            }

            index = 0;

            // Decode ID and state flags
            for (int i = 0; i < measurementCount; i++)
            {
                uint value = NativeEndianOrder.Default.ToUInt32(buffer, index);

                measurements[i] = new CompactMeasurement(signalIndexCache, includeTime)
                {
                    CompactStateFlags = (byte)(value >> 16),
                    RuntimeID         = (ushort)value
                };

                index += 4;
            }

            // Decode values
            for (int i = 0; i < measurementCount; i++)
            {
                measurements[i].Value = NativeEndianOrder.Default.ToSingle(buffer, index);
                index += 4;
            }

            if (includeTime)
            {
                // Decode timestamps
                for (int i = 0; i < measurementCount; i++)
                {
                    measurements[i].Timestamp = NativeEndianOrder.Default.ToInt64(buffer, index);
                    index += 8;
                }
            }

            return(measurements);
        }
コード例 #7
0
ファイル: CompactMeasurement.cs プロジェクト: lyrain2009/gsf
        /// <summary>
        /// Attempts to compress payload of <see cref="CompactMeasurement"/> values onto the <paramref name="destination"/> stream.
        /// </summary>
        /// <param name="compactMeasurements">Payload of <see cref="CompactMeasurement"/> values.</param>
        /// <param name="destination">Memory based <paramref name="destination"/> stream to hold compressed payload.</param>
        /// <param name="compressionStrength">Compression strength to use.</param>
        /// <param name="includeTime">Flag that determines if time should be included in the compressed payload.</param>
        /// <param name="flags">Current <see cref="DataPacketFlags"/>.</param>
        /// <returns><c>true</c> if payload was compressed and encoded onto <paramref name="destination"/> stream; otherwise <c>false</c>.</returns>
        /// <remarks>
        /// <para>
        /// Compressed payload will only be encoded onto <paramref name="destination"/> stream if compressed size would be smaller
        /// than normal serialized size.
        /// </para>
        /// <para>
        /// As an optimization this function uses a compression method that uses pointers to native structures, as such the
        /// endian order encoding of the compressed data will always be in the native-endian order of the operating system.
        /// This will be an important consideration when writing a endian order neutral payload decompressor. To help with
        /// this the actual endian order used during compression is marked in the data flags. However, measurements values
        /// are consistently encoded in big-endian order prior to buffer compression.
        /// </para>
        /// </remarks>
        public static bool CompressPayload(this IEnumerable <CompactMeasurement> compactMeasurements, BlockAllocatedMemoryStream destination, byte compressionStrength, bool includeTime, ref DataPacketFlags flags)
        {
            // Instantiate a buffer that is larger than we'll need
            byte[] buffer = new byte[ushort.MaxValue];

            // Go ahead an enumerate all the measurements - this will cast all values to compact measurements
            CompactMeasurement[] measurements = compactMeasurements.ToArray();
            int measurementCount = measurements.Length;
            int sizeToBeat       = measurementCount * measurements[0].BinaryLength;
            int index            = 0;

            // Encode compact state flags and runtime IDs together --
            // Together these are three bytes, so we pad with a zero byte.
            // The zero byte and state flags are considered to be more compressible
            // than the runtime ID, so these are stored in the higher order bytes.
            for (int i = 0; i < measurementCount; i++)
            {
                uint value = ((uint)measurements[i].CompactStateFlags << 16) | measurements[i].RuntimeID;
                index += NativeEndianOrder.Default.CopyBytes(value, buffer, index);
            }

            // Encode values
            for (int i = 0; i < measurementCount; i++)
            {
                // Encode using adjusted value (accounts for adder and multiplier)
                index += NativeEndianOrder.Default.CopyBytes((float)measurements[i].AdjustedValue, buffer, index);
            }

            if (includeTime)
            {
                // Encode timestamps
                for (int i = 0; i < measurementCount; i++)
                {
                    // Since large majority of 8-byte tick values will be repeated, they should compress well
                    index += NativeEndianOrder.Default.CopyBytes((long)measurements[i].Timestamp, buffer, index);
                }
            }

            // Attempt to compress buffer
            int compressedSize = PatternCompressor.CompressBuffer(buffer, 0, index, ushort.MaxValue, compressionStrength);

            // Only encode compressed buffer if compression actually helped payload size
            if (compressedSize <= sizeToBeat)
            {
                // Set payload compression flag
                flags |= DataPacketFlags.Compressed;

                // Make sure decompressor knows original endian encoding order
                if (BitConverter.IsLittleEndian)
                {
                    flags |= DataPacketFlags.LittleEndianCompression;
                }
                else
                {
                    flags &= ~DataPacketFlags.LittleEndianCompression;
                }

                // Copy compressed payload onto destination stream
                destination.Write(buffer, 0, compressedSize);
                return(true);
            }

            // Clear payload compression flag
            flags &= ~DataPacketFlags.Compressed;
            return(false);
        }
コード例 #8
0
ファイル: CompactMeasurement.cs プロジェクト: avs009/gsf
        /// <summary>
        /// Decompresses <see cref="CompactMeasurement"/> values from the given <paramref name="source"/> buffer.
        /// </summary>
        /// <param name="source">Buffer with compressed <see cref="CompactMeasurement"/> payload.</param>
        /// <param name="signalIndexCache">Current <see cref="SignalIndexCache"/>.</param>
        /// <param name="index">Index into buffer where compressed payload begins.</param>
        /// <param name="dataLength">Length of all data within <paramref name="source"/> buffer.</param>
        /// <param name="measurementCount">Number of compressed measurements in the payload.</param>
        /// <param name="includeTime">Flag that determines if timestamps as included in the payload.</param>
        /// <param name="flags">Current <see cref="DataPacketFlags"/>.</param>
        /// <returns>Decompressed <see cref="CompactMeasurement"/> values from the given <paramref name="source"/> buffer.</returns>
        public static CompactMeasurement[] DecompressPayload(this byte[] source, SignalIndexCache signalIndexCache, int index, int dataLength, int measurementCount, bool includeTime, DataPacketFlags flags)
        {
            CompactMeasurement[] measurements = new CompactMeasurement[measurementCount];
            byte[] buffer = null;

            try
            {
                // Actual data length has to take into account response byte and in-response-to server command byte in the payload header
                //int dataLength = length - index - 2;
                int bufferLength = PatternDecompressor.MaximumSizeDecompressed(dataLength);

                // Copy source data into a decompression buffer
                buffer = BufferPool.TakeBuffer(bufferLength);
                Buffer.BlockCopy(source, index, buffer, 0, dataLength);

                // Check that OS endian-order matches endian-order of compressed data
                if (!(BitConverter.IsLittleEndian && (flags & DataPacketFlags.LittleEndianCompression) > 0))
                {
                    // TODO: Set a flag, e.g., Endianness decompressAs, to pass into pattern decompressor so it
                    // can be modified to decompress a payload that is non-native Endian order
                    throw new NotImplementedException("Cannot currently decompress payload that is not in native endian-order.");
                }

                // Attempt to decompress buffer
                int uncompressedSize = PatternDecompressor.DecompressBuffer(buffer, 0, dataLength, bufferLength);

                if (uncompressedSize == 0)
                    throw new InvalidOperationException("Failed to decompress payload buffer - possible data corruption.");

                index = 0;

                // Decode ID and state flags
                for (int i = 0; i < measurementCount; i++)
                {
                    uint value = NativeEndianOrder.Default.ToUInt32(buffer, index);

                    measurements[i] = new CompactMeasurement(signalIndexCache, includeTime)
                    {
                        CompactStateFlags = (byte)(value >> 16),
                        RuntimeID = (ushort)value
                    };

                    index += 4;
                }

                // Decode values
                for (int i = 0; i < measurementCount; i++)
                {
                    measurements[i].Value = NativeEndianOrder.Default.ToSingle(buffer, index);
                    index += 4;
                }

                if (includeTime)
                {
                    // Decode timestamps
                    for (int i = 0; i < measurementCount; i++)
                    {
                        measurements[i].Timestamp = NativeEndianOrder.Default.ToInt64(buffer, index);
                        index += 8;
                    }
                }
            }
            finally
            {
                if ((object)buffer != null)
                    BufferPool.ReturnBuffer(buffer);
            }

            return measurements;
        }
コード例 #9
0
ファイル: CompactMeasurement.cs プロジェクト: avs009/gsf
        /// <summary>
        /// Attempts to compress payload of <see cref="CompactMeasurement"/> values onto the <paramref name="destination"/> stream.
        /// </summary>
        /// <param name="compactMeasurements">Payload of <see cref="CompactMeasurement"/> values.</param>
        /// <param name="destination">Memory based <paramref name="destination"/> stream to hold compressed payload.</param>
        /// <param name="compressionStrength">Compression strength to use.</param>
        /// <param name="includeTime">Flag that determines if time should be included in the compressed payload.</param>
        /// <param name="flags">Current <see cref="DataPacketFlags"/>.</param>
        /// <returns><c>true</c> if payload was compressed and encoded onto <paramref name="destination"/> stream; otherwise <c>false</c>.</returns>
        /// <remarks>
        /// <para>
        /// Compressed payload will only be encoded onto <paramref name="destination"/> stream if compressed size would be smaller
        /// than normal serialized size.
        /// </para>
        /// <para>
        /// As an optimization this function uses a compression method that uses pointers to native structures, as such the
        /// endian order encoding of the compressed data will always be in the native-endian order of the operating system.
        /// This will be an important consideration when writing a endian order neutral payload decompressor. To help with
        /// this the actual endian order used during compression is marked in the data flags. However, measurements values
        /// are consistently encoded in big-endian order prior to buffer compression.
        /// </para>
        /// </remarks>
        public static bool CompressPayload(this IEnumerable<CompactMeasurement> compactMeasurements, MemoryStream destination, byte compressionStrength, bool includeTime, ref DataPacketFlags flags)
        {
            byte[] buffer = null;

            try
            {
                // Get a buffer that is larger than we'll need
                buffer = BufferPool.TakeBuffer(ushort.MaxValue);

                // Go ahead an enumerate all the measurements - this will cast all values to compact measurements
                CompactMeasurement[] measurements = compactMeasurements.ToArray();
                int measurementCount = measurements.Length;
                int sizeToBeat = measurementCount * measurements[0].BinaryLength;
                int index = 0;

                // Encode compact state flags and runtime IDs together --
                // Together these are three bytes, so we pad with a zero byte.
                // The zero byte and state flags are considered to be more compressible
                // than the runtime ID, so these are stored in the higher order bytes.
                for (int i = 0; i < measurementCount; i++)
                {
                    uint value = ((uint)measurements[i].CompactStateFlags << 16) | measurements[i].RuntimeID;
                    index += NativeEndianOrder.Default.CopyBytes(value, buffer, index);
                }

                // Encode values
                for (int i = 0; i < measurementCount; i++)
                {
                    // Encode using adjusted value (accounts for adder and multiplier)
                    index += NativeEndianOrder.Default.CopyBytes((float)measurements[i].AdjustedValue, buffer, index);
                }

                if (includeTime)
                {
                    // Encode timestamps
                    for (int i = 0; i < measurementCount; i++)
                    {
                        // Since large majority of 8-byte tick values will be repeated, they should compress well
                        index += NativeEndianOrder.Default.CopyBytes((long)measurements[i].Timestamp, buffer, index);
                    }
                }

                // Attempt to compress buffer
                int compressedSize = PatternCompressor.CompressBuffer(buffer, 0, index, ushort.MaxValue, compressionStrength);

                // Only encode compressed buffer if compression actually helped payload size
                if (compressedSize <= sizeToBeat)
                {
                    // Set payload compression flag
                    flags |= DataPacketFlags.Compressed;

                    // Make sure decompressor knows original endian encoding order
                    if (BitConverter.IsLittleEndian)
                        flags |= DataPacketFlags.LittleEndianCompression;
                    else
                        flags &= ~DataPacketFlags.LittleEndianCompression;

                    // Copy compressed payload onto destination stream
                    destination.Write(buffer, 0, compressedSize);
                    return true;
                }

                // Clear payload compression flag
                flags &= ~DataPacketFlags.Compressed;
                return false;
            }
            finally
            {
                if ((object)buffer != null)
                    BufferPool.ReturnBuffer(buffer);
            }
        }