GetSignalIndex() public method

Gets runtime signal index for given Guid signal ID.
public GetSignalIndex ( MeasurementKey key ) : ushort
key MeasurementKey The used to lookup associated runtime signal index.
return ushort
        private void ProcessTSSCMeasurements(IFrame frame)
        {
            lock (m_tsscSyncLock)
            {
                try
                {
                    if (!Enabled)
                    {
                        return;
                    }

                    if ((object)m_tsscEncoder == null || m_resetTsscEncoder)
                    {
                        m_resetTsscEncoder  = false;
                        m_tsscEncoder       = new TsscEncoder();
                        m_tsscWorkingBuffer = new byte[32 * 1024];
                        OnStatusMessage(MessageLevel.Info, $"TSSC algorithm reset before sequence number: {m_tsscSequenceNumber}", "TSSC");
                        m_tsscSequenceNumber = 0;
                        m_tsscEncoder.SetBuffer(m_tsscWorkingBuffer, 0, m_tsscWorkingBuffer.Length);
                    }
                    else
                    {
                        m_tsscEncoder.SetBuffer(m_tsscWorkingBuffer, 0, m_tsscWorkingBuffer.Length);
                    }

                    int count = 0;

                    foreach (IMeasurement measurement in frame.Measurements.Values)
                    {
                        ushort index = m_signalIndexCache.GetSignalIndex(measurement.Key);

                        if (!m_tsscEncoder.TryAddMeasurement(index, measurement.Timestamp.Value, (uint)measurement.StateFlags, (float)measurement.AdjustedValue))
                        {
                            SendTSSCPayload(frame.Timestamp, count);
                            count = 0;
                            m_tsscEncoder.SetBuffer(m_tsscWorkingBuffer, 0, m_tsscWorkingBuffer.Length);

                            // This will always succeed
                            m_tsscEncoder.TryAddMeasurement(index, measurement.Timestamp.Value, (uint)measurement.StateFlags, (float)measurement.AdjustedValue);
                        }

                        count++;
                    }

                    if (count > 0)
                    {
                        SendTSSCPayload(frame.Timestamp, count);
                    }

                    // Update latency statistics
                    long publishTime = DateTime.UtcNow.Ticks;
                    m_parent.UpdateLatencyStatistics(frame.Measurements.Values.Select(m => (long)(publishTime - m.Timestamp)));
                }
                catch (Exception ex)
                {
                    string message = $"Error processing measurements: {ex.Message}";
                    OnProcessException(MessageLevel.Info, new InvalidOperationException(message, ex));
                }
            }
        }
Example #2
0
        /// <summary>
        /// Generates binary image of the <see cref="CompactMeasurement"/> and copies it into the given buffer, for <see cref="ISupportBinaryImage.BinaryLength"/> bytes.
        /// </summary>
        /// <param name="buffer">Buffer used to hold generated binary image of the source object.</param>
        /// <param name="startIndex">0-based starting index in the <paramref name="buffer"/> to start writing.</param>
        /// <returns>The number of bytes written to the <paramref name="buffer"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="startIndex"/> or <see cref="ISupportBinaryImage.BinaryLength"/> is less than 0 -or-
        /// <paramref name="startIndex"/> and <see cref="ISupportBinaryImage.BinaryLength"/> will exceed <paramref name="buffer"/> length.
        /// </exception>
        /// <remarks>
        /// <para>
        /// Field:     Bytes: <br/>
        /// --------   -------<br/>
        ///  Flags        1   <br/>
        ///   ID          2   <br/>
        ///  Value        4   <br/>
        ///  [Time]       2?  <br/>
        /// </para>
        /// <para>
        /// Constant Length = 7<br/>
        /// Variable Length = 0, 2, 4 or 8 (i.e., total size is 7, 9, 11 or 15)
        /// </para>
        /// </remarks>
        public int GenerateBinaryImage(byte[] buffer, int startIndex)
        {
            // Call to binary length property caches result of m_usingBaseTimeOffset
            int length = BinaryLength;

            buffer.ValidateParameters(startIndex, length);

            // Encode compact state flags
            CompactMeasurementStateFlags flags = StateFlags.MapToCompactFlags();

            if (m_timeIndex != 0)
            {
                flags |= CompactMeasurementStateFlags.TimeIndex;
            }

            if (m_usingBaseTimeOffset)
            {
                flags |= CompactMeasurementStateFlags.BaseTimeOffset;
            }

            // Added flags to beginning of buffer
            buffer[startIndex++] = (byte)flags;

            // Encode runtime ID
            EndianOrder.BigEndian.CopyBytes(m_signalIndexCache.GetSignalIndex(ID), buffer, startIndex);

            startIndex += 2;

            // Encode adjusted value (accounts for adder and multipler)
            EndianOrder.BigEndian.CopyBytes((float)AdjustedValue, buffer, startIndex);
            startIndex += 4;

            if (m_includeTime)
            {
                if (m_usingBaseTimeOffset)
                {
                    if (m_useMillisecondResolution)
                    {
                        // Encode 2-byte millisecond offset timestamp
                        EndianOrder.BigEndian.CopyBytes((ushort)(Timestamp - m_baseTimeOffsets[m_timeIndex]).ToMilliseconds(), buffer, startIndex);
                    }
                    else
                    {
                        // Encode 4-byte ticks offset timestamp
                        EndianOrder.BigEndian.CopyBytes((uint)((long)Timestamp - m_baseTimeOffsets[m_timeIndex]), buffer, startIndex);
                    }
                }
                else
                {
                    // Encode 8-byte full fidelity timestamp
                    EndianOrder.BigEndian.CopyBytes((long)Timestamp, buffer, startIndex);
                }
            }

            return(length);
        }
Example #3
0
        private void ProcessMeasurements(IEnumerable <IMeasurement> measurements)
        {
            // Includes data packet flags and measurement count
            const int PacketHeaderSize = DataPublisher.ClientResponseHeaderSize + 5;

            List <IBinaryMeasurement> packet;
            int packetSize;

            bool usePayloadCompression;
            bool useCompactMeasurementFormat;

            BufferBlockMeasurement bufferBlockMeasurement;

            byte[] bufferBlock;
            ushort bufferBlockSignalIndex;

            IBinaryMeasurement binaryMeasurement;
            int binaryLength;

            try
            {
                if (!Enabled)
                {
                    return;
                }

                packet     = new List <IBinaryMeasurement>();
                packetSize = PacketHeaderSize;

                usePayloadCompression       = m_usePayloadCompression;
                useCompactMeasurementFormat = m_useCompactMeasurementFormat || usePayloadCompression;

                foreach (IMeasurement measurement in measurements)
                {
                    bufferBlockMeasurement = measurement as BufferBlockMeasurement;

                    if ((object)bufferBlockMeasurement != null)
                    {
                        // Still sending buffer block measurements to client; we are expecting
                        // confirmations which will indicate whether retransmission is necessary,
                        // so we will restart the retransmission timer
                        m_bufferBlockRetransmissionTimer.Stop();

                        // Handle buffer block measurements as a special case - this can be any kind of data,
                        // measurement subscriber will need to know how to interpret buffer
                        bufferBlock = new byte[6 + bufferBlockMeasurement.Length];

                        // Prepend sequence number
                        BigEndian.CopyBytes(m_bufferBlockSequenceNumber, bufferBlock, 0);
                        m_bufferBlockSequenceNumber++;

                        // Copy signal index into buffer
                        bufferBlockSignalIndex = m_signalIndexCache.GetSignalIndex(bufferBlockMeasurement.ID);
                        BigEndian.CopyBytes(bufferBlockSignalIndex, bufferBlock, 4);

                        // Append measurement data and send
                        Buffer.BlockCopy(bufferBlockMeasurement.Buffer, 0, bufferBlock, 6, bufferBlockMeasurement.Length);
                        m_parent.SendClientResponse(m_workingBuffer, m_clientID, ServerResponse.BufferBlock, ServerCommand.Subscribe, bufferBlock);

                        lock (m_bufferBlockCacheLock)
                        {
                            // Cache buffer block for retransmission
                            m_bufferBlockCache.Add(bufferBlock);
                        }

                        // Start the retransmission timer in case we never receive a confirmation
                        m_bufferBlockRetransmissionTimer.Start();
                    }
                    else
                    {
                        // Serialize the current measurement.
                        if (useCompactMeasurementFormat)
                        {
                            binaryMeasurement = new CompactMeasurement(measurement, m_signalIndexCache, m_includeTime, m_baseTimeOffsets, m_timeIndex, m_useMillisecondResolution);
                        }
                        else
                        {
                            binaryMeasurement = new SerializableMeasurement(measurement, m_parent.GetClientEncoding(m_clientID));
                        }

                        // Determine the size of the measurement in bytes.
                        binaryLength = binaryMeasurement.BinaryLength;

                        // If the current measurement will not fit in the packet based on the max
                        // packet size, process the current packet and start a new packet.
                        if (packetSize + binaryLength > DataPublisher.MaxPacketSize)
                        {
                            ProcessBinaryMeasurements(packet, useCompactMeasurementFormat, usePayloadCompression);
                            packet.Clear();
                            packetSize = PacketHeaderSize;
                        }

                        // Add the current measurement to the packet.
                        packet.Add(binaryMeasurement);
                        packetSize += binaryLength;
                    }
                }

                // Process the remaining measurements.
                if (packet.Count > 0)
                {
                    ProcessBinaryMeasurements(packet, useCompactMeasurementFormat, usePayloadCompression);
                }

                IncrementProcessedMeasurements(measurements.Count());

                // Update latency statistics
                m_parent.UpdateLatencyStatistics(measurements.Select(m => (long)(m_lastPublishTime - m.Timestamp)));
            }
            catch (Exception ex)
            {
                string message = string.Format("Error processing measurements: {0}", ex.Message);
                OnProcessException(new InvalidOperationException(message, ex));
            }
        }