private void ProcessMeasurements(IEnumerable <IMeasurement> measurements) { List <ISupportBinaryImage> packet = new List <ISupportBinaryImage>(); bool useCompactMeasurementFormat = m_useCompactMeasurementFormat; int packetSize = 5; // Wait for any external events, if needed WaitForExternalEvents(); // If a set of base times has not yet been initialized, initialize a set by rotating if (!m_initializedBaseTimeOffsets) { if (m_parent.UseBaseTimeOffsets) { RotateBaseTimes(); } m_initializedBaseTimeOffsets = true; } foreach (IMeasurement measurement in measurements) { ISupportBinaryImage binaryMeasurement; int binaryLength; // 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); packet.Clear(); packetSize = 5; } // Add the current measurement to the packet. packet.Add(binaryMeasurement); packetSize += binaryLength; } // Process the remaining measurements. ProcessBinaryMeasurements(packet, useCompactMeasurementFormat); }
/// <summary> /// Publish <see cref="IFrame"/> of time-aligned collection of <see cref="IMeasurement"/> values that arrived within the /// concentrator's defined <see cref="ConcentratorBase.LagTime"/>. /// </summary> /// <param name="frame"><see cref="IFrame"/> of measurements with the same timestamp that arrived within <see cref="ConcentratorBase.LagTime"/> that are ready for processing.</param> /// <param name="index">Index of <see cref="IFrame"/> within a second ranging from zero to <c><see cref="ConcentratorBase.FramesPerSecond"/> - 1</c>.</param> protected override void PublishFrame(IFrame frame, int index) { if (!m_disposed) { List <ISupportBinaryImage> packet = new List <ISupportBinaryImage>(); bool useCompactMeasurementFormat = m_useCompactMeasurementFormat; long frameLevelTimestamp = frame.Timestamp; int packetSize = 13; foreach (IMeasurement measurement in frame.Measurements.Values) { ISupportBinaryImage binaryMeasurement; int binaryLength; // Serialize the current measurement. if (useCompactMeasurementFormat) { binaryMeasurement = new CompactMeasurement(measurement, m_signalIndexCache, false, null, 0, false); } else { binaryMeasurement = new SerializableMeasurement(measurement, m_parent.GetClientEncoding(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 packet and start a new one. if (packetSize + binaryLength > DataPublisher.MaxPacketSize) { ProcessBinaryMeasurements(packet, frameLevelTimestamp, useCompactMeasurementFormat); packet.Clear(); packetSize = 13; } // Add the measurement to the packet. packet.Add(binaryMeasurement); packetSize += binaryLength; } // Process the remaining measurements. ProcessBinaryMeasurements(packet, frameLevelTimestamp, useCompactMeasurementFormat); } }
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)); } }
/// <summary> /// Publish <see cref="IFrame"/> of time-aligned collection of <see cref="IMeasurement"/> values that arrived within the /// concentrator's defined <see cref="ConcentratorBase.LagTime"/>. /// </summary> /// <param name="frame"><see cref="IFrame"/> of measurements with the same timestamp that arrived within <see cref="ConcentratorBase.LagTime"/> that are ready for processing.</param> /// <param name="index">Index of <see cref="IFrame"/> within a second ranging from zero to <c><see cref="ConcentratorBase.FramesPerSecond"/> - 1</c>.</param> protected override void PublishFrame(IFrame frame, int index) { if ((object)m_parent == null || m_disposed) { return; } if (m_usePayloadCompression && m_compressionModes.HasFlag(CompressionModes.TSSC)) { ProcessTSSCMeasurements(frame); return; } // Includes data packet flags, frame level timestamp and measurement count const int PacketHeaderSize = DataPublisher.ClientResponseHeaderSize + 13; List <IBinaryMeasurement> packet = new List <IBinaryMeasurement>(); bool usePayloadCompression = m_usePayloadCompression; bool useCompactMeasurementFormat = m_useCompactMeasurementFormat || usePayloadCompression; long frameLevelTimestamp = frame.Timestamp; BufferBlockMeasurement bufferBlockMeasurement; IBinaryMeasurement binaryMeasurement; byte[] bufferBlock; int binaryLength; int packetSize = PacketHeaderSize; long publishTime; foreach (IMeasurement measurement in frame.Measurements.Values) { 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[4 + bufferBlockMeasurement.Length]; // Prepend sequence number BigEndian.CopyBytes(m_bufferBlockSequenceNumber, bufferBlock, 0); m_bufferBlockSequenceNumber++; // Append measurement data and send Buffer.BlockCopy(bufferBlockMeasurement.Buffer, 0, bufferBlock, 4, bufferBlockMeasurement.Length); m_parent.SendClientResponse(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, false); } else { binaryMeasurement = new SerializableMeasurement(measurement, m_parent.GetClientEncoding(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 packet and start a new one. if (packetSize + binaryLength > DataPublisher.MaxPacketSize) { ProcessBinaryMeasurements(packet, frameLevelTimestamp, useCompactMeasurementFormat, usePayloadCompression); packet.Clear(); packetSize = PacketHeaderSize; } // Add the measurement to the packet. packet.Add(binaryMeasurement); packetSize += binaryLength; } } // Process the remaining measurements. if (packet.Count > 0) { ProcessBinaryMeasurements(packet, frameLevelTimestamp, useCompactMeasurementFormat, usePayloadCompression); } // Update latency statistics publishTime = DateTime.UtcNow.Ticks; m_parent.UpdateLatencyStatistics(frame.Measurements.Values.Select(m => (long)(publishTime - m.Timestamp))); }