private UnsynchronizedSubscriptionInfo FromLocallySynchronizedInfo(SynchronizedSubscriptionInfo info) { return new UnsynchronizedSubscriptionInfo(false) { FilterExpression = info.FilterExpression, UseCompactMeasurementFormat = info.UseCompactMeasurementFormat, UdpDataChannel = info.UdpDataChannel, DataChannelLocalPort = info.DataChannelLocalPort, LagTime = info.LagTime, LeadTime = info.LeadTime, UseLocalClockAsRealTime = false, UseMillisecondResolution = info.UseMillisecondResolution, StartTime = info.StartTime, StopTime = info.StopTime, ConstraintParameters = info.ConstraintParameters, ProcessingInterval = info.ProcessingInterval, ExtraConnectionStringParameters = info.ExtraConnectionStringParameters }; }
/// <summary> /// Subscribes (or re-subscribes) to a data publisher for a synchronized set of data points. /// </summary> /// <param name="info">Configuration object that defines the subscription.</param> /// <returns><c>true</c> if subscribe transmission was successful; otherwise <c>false</c>.</returns> public bool SynchronizedSubscribe(SynchronizedSubscriptionInfo info) { StringBuilder connectionString = new StringBuilder(); AssemblyInfo assemblyInfo = AssemblyInfo.ExecutingAssembly; // Dispose of any previously established local concentrator DisposeLocalConcentrator(); if (info.RemotelySynchronized) { connectionString.AppendFormat("framesPerSecond={0};", info.FramesPerSecond); connectionString.AppendFormat("lagTime={0};", info.LagTime); connectionString.AppendFormat("leadTime={0};", info.LeadTime); connectionString.AppendFormat("includeTime=false;"); connectionString.AppendFormat("useLocalClockAsRealTime={0};", info.UseLocalClockAsRealTime); connectionString.AppendFormat("ignoreBadTimestamps={0};", info.IgnoreBadTimestamps); connectionString.AppendFormat("allowSortsByArrival={0};", info.AllowSortsByArrival); connectionString.AppendFormat("timeResolution={0};", info.TimeResolution); connectionString.AppendFormat("allowPreemptivePublishing={0};", info.AllowPreemptivePublishing); connectionString.AppendFormat("requestNaNValueFilter={0};", info.RequestNaNValueFilter); connectionString.AppendFormat("downsamplingMethod={0};", info.DownsamplingMethod); connectionString.AppendFormat("processingInterval={0};", info.ProcessingInterval); connectionString.AppendFormat("assemblyInfo={{source={0};version={1}.{2}.{3};buildDate={4}}};", assemblyInfo.Name, assemblyInfo.Version.Major, assemblyInfo.Version.Minor, assemblyInfo.Version.Build, assemblyInfo.BuildDate.ToString("yyyy-MM-dd HH:mm:ss")); if (!string.IsNullOrWhiteSpace(info.FilterExpression)) connectionString.AppendFormat("inputMeasurementKeys={{{0}}};", info.FilterExpression); if (info.UdpDataChannel) connectionString.AppendFormat("dataChannel={{localport={0}}};", info.DataChannelLocalPort); if (!string.IsNullOrWhiteSpace(info.StartTime)) connectionString.AppendFormat("startTimeConstraint={0};", info.StartTime); if (!string.IsNullOrWhiteSpace(info.StopTime)) connectionString.AppendFormat("stopTimeConstraint={0};", info.StopTime); if (!string.IsNullOrWhiteSpace(info.ConstraintParameters)) connectionString.AppendFormat("timeConstraintParameters={0};", info.ConstraintParameters); if (!string.IsNullOrWhiteSpace(info.ExtraConnectionStringParameters)) connectionString.AppendFormat("{0};", info.ExtraConnectionStringParameters); return Subscribe(true, info.UseCompactMeasurementFormat, connectionString.ToString()); } // Locally concentrated subscription simply uses an unsynchronized subscription and concentrates the // measurements on the subscriber side if (Subscribe(FromLocallySynchronizedInfo(info))) { // Establish a local concentrator to synchronize received measurements LocalConcentrator localConcentrator = new LocalConcentrator(this); localConcentrator.ProcessException += m_localConcentrator_ProcessException; localConcentrator.FramesPerSecond = info.FramesPerSecond; localConcentrator.LagTime = info.LagTime; localConcentrator.LeadTime = info.LeadTime; localConcentrator.UseLocalClockAsRealTime = info.UseLocalClockAsRealTime; localConcentrator.IgnoreBadTimestamps = info.IgnoreBadTimestamps; localConcentrator.AllowSortsByArrival = info.AllowSortsByArrival; localConcentrator.TimeResolution = info.TimeResolution; localConcentrator.AllowPreemptivePublishing = info.AllowPreemptivePublishing; localConcentrator.DownsamplingMethod = info.DownsamplingMethod; localConcentrator.UsePrecisionTimer = false; // Parse time constraints, if defined DateTime startTimeConstraint = !string.IsNullOrWhiteSpace(info.StartTime) ? ParseTimeTag(info.StartTime) : DateTime.MinValue; DateTime stopTimeConstraint = !string.IsNullOrWhiteSpace(info.StopTime) ? ParseTimeTag(info.StopTime) : DateTime.MaxValue; // When processing historical data, timestamps should not be evaluated for reasonability if (startTimeConstraint != DateTime.MinValue || stopTimeConstraint != DateTime.MaxValue) { localConcentrator.PerformTimestampReasonabilityCheck = false; localConcentrator.LeadTime = double.MaxValue; } // Assign alternate processing interval, if defined if (info.ProcessingInterval != -1) localConcentrator.ProcessingInterval = info.ProcessingInterval; // Start local concentrator localConcentrator.Start(); // Move concentrator to member variable Interlocked.Exchange(ref m_localConcentrator, localConcentrator); return true; } return false; }