/// <summary>We retrieve adjusted measurement values within time tolerance of concentrator real-time.</summary> /// <param name="key">An <see cref="MeasurementKey"/> representing the measurement key.</param> /// <returns>A <see cref="Double"/> representing the adjusted measurement value.</returns> public double this[MeasurementKey key] { get { return Measurement(key).GetAdjustedValue(m_parent.RealTime); } }
/// <summary> /// Initializes <see cref="VirtualInputAdapter"/>. /// </summary> public override void Initialize() { // In case user defines no inputs or outputs for virutal adapter, we "turn off" interaction with any // other real-time adapters by removing this virtual adapter from external routes. To accomplish this // we expose I/O demands for an undefined measurement. Leaving values assigning to null would mean // that this adapter desires a full "broadcast" of all data - and hence routing demands from all. // User can override if desired using standard connection string parameters for I/O measurements. InputMeasurementKeys = new MeasurementKey[] { MeasurementKey.Undefined }; OutputMeasurements = new Measurement[] { Measurement.Undefined }; base.Initialize(); }
public Measurement(int id, string source, double value, double adder, double multiplier, long ticks) { m_id = id; m_source = source; m_key = new MeasurementKey(m_id, m_source); m_value = value; m_adder = adder; m_multiplier = multiplier; m_ticks = ticks; m_valueQualityIsGood = true; m_timestampQualityIsGood = true; }
private Metadata(DataRow row) { MeasurementKey measurementKey; Guid.TryParse(row["SignalID"].ToString(), out SignalID); MeasurementKey.TryParse(row["ID"].ToString(), out measurementKey); PointID = measurementKey.ID; PointTag = row["PointTag"].ToString(); SignalReference = row["SignalReference"].ToString(); DeviceName = row["DeviceAcronym"].ToString(); SignalAcronym = row["SignalAcronym"].ToString(); Description = row["Description"].ToString(); }
// Converts the given row of CSV data to a single measurement. private IMeasurement FromCSV(string csv) { string[] split = csv.Split(','); DateTime timestamp = DateTime.Parse(split[0]); Guid signalID = Guid.Parse(split[1]); double value = double.Parse(split[2]); return(new Measurement() { Metadata = MeasurementKey.LookUpBySignalID(signalID).Metadata, Timestamp = timestamp, Value = value }); }
// Adds the given mapping to the key-variable map. private void AddMapping(MeasurementKey key, string alias) { if (m_variableNames.Contains(alias)) { throw new ArgumentException($"Variable name is not unique: {alias}"); } if (alias.Equals("TIME", StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException("Variable name \"TIME\" is reserved."); } m_variableNames.Add(alias); m_keyMapping.Add(key, alias); }
/// <summary> /// Creates a new instance of the <see cref="SignalBuffer"/> class. /// </summary> /// <param name="key">The key which identifies the signal which is buffered.</param> public SignalBuffer(MeasurementKey key) { const int Sentinel = -1; m_key = key; m_blocks = new List <MeasurementBlock>(); m_blocks.Add(new MeasurementBlock(BlockSize)); m_removedBlockCounts = new RollingWindow <int>(StatWindow); m_blockLock = new object(); for (int i = 0; i < StatWindow; i++) { m_removedBlockCounts.Add(Sentinel); } }
// Add a measurement to the list of out of range measurements corresponding to the given key. private void AddOutOfRangeMeasurement(MeasurementKey key, IMeasurement measurement) { lock (m_outOfRangeMeasurements) { LinkedList <IMeasurement> outOfRangeList; if (!m_outOfRangeMeasurements.TryGetValue(key, out outOfRangeList)) { outOfRangeList = new LinkedList <IMeasurement>(); m_outOfRangeMeasurements.Add(key, outOfRangeList); } outOfRangeList.AddLast(measurement); } }
/// <summary> /// Returns a new measurement equivalent to the one being wrapped. /// </summary> /// <returns>The wrapped measurement.</returns> public IMeasurement GetMeasurement() { Guid signalID = Guid.Parse(SignalID); IMeasurement measurement = new Measurement() { Adder = Adder, Key = MeasurementKey.LookUpOrCreate(signalID, Source, unchecked ((uint)ID)), Multiplier = Multiplier, TagName = TagName, Timestamp = Timestamp, Value = Value }; return(measurement); }
// Adds a variable to the key-variable map which has not been explicitly aliased. private void AddNotAliasedVariable(string token) { token = token.Trim(); m_nonAliasedTokens.Add(-token.Length, token); MeasurementKey key = GetKey(token); string alias = token.ReplaceCharacters('_', c => !char.IsLetterOrDigit(c)); // Ensure that the generated alias is unique while (m_variableNames.Contains(alias)) { alias += "_"; } AddMapping(key, alias); }
protected MetaValues CreateMetaValues(FieldMapping fieldMapping) { if (fieldMapping.RelativeTime != 0.0M) { AlignmentCoordinator.SampleWindow sampleWindow = CreateSampleWindow(fieldMapping); MeasurementKey key = m_keys[m_keyIndex++].Single(); return(AlignmentCoordinator.CreateMetaValue(key, CurrentFrameTime, sampleWindow)); } return(new MetaValues() { ID = m_keys[m_keyIndex++].Single().SignalID, Timestamp = m_currentFrameTime, Flags = MeasurementFlags.CalculatedValue }); }
/// <summary> /// Gets signal type for given measurement key /// </summary> /// <param name="dataSource">Target <see cref="DataSet"/>.</param> /// <param name="key">Source <see cref="MeasurementKey"/>.</param> /// <param name="measurementTable">Measurement table name used for meta-data lookup.</param> /// <returns><see cref="SignalType"/> as defined for measurement key in data source.</returns> public static SignalType GetSignalType(this DataSet dataSource, MeasurementKey key, string measurementTable = "ActiveMeasurements") { if (dataSource == null) { throw new ArgumentNullException(nameof(dataSource)); } DataRow record = dataSource.LookupMetadata(key.SignalID, measurementTable); if (record != null && Enum.TryParse(record["SignalType"].ToString(), out SignalType signalType)) { return(signalType); } return(SignalType.NONE); }
/// <summary> /// Queries the signal buffer for the measurement whose timestamp is nearest the given timestamp, /// but only returns the measurement if its timestamp falls within a specified tolerance around the given timestamp. /// </summary> /// <param name="key">The key which identifies the signal to be queried.</param> /// <param name="timestamp">The timestamp of the measurement to be queried.</param> /// <param name="tolerance">The tolerance that determines whether the nearest measurement is valid.</param> /// <returns>The measurement whose timestamp is nearest the given timestamp or null if the measurement's timestamp falls outside the given tolerance.</returns> public IMeasurement QuerySignalBuffer(MeasurementKey key, DateTime timestamp, TimeSpan tolerance) { IMeasurement nearestMeasurement = QuerySignalBuffer(key, timestamp); if ((object)nearestMeasurement == null) { return(null); } if (nearestMeasurement.Timestamp < (timestamp - tolerance).Ticks || nearestMeasurement.Timestamp > (timestamp + tolerance).Ticks) { return(null); } return(nearestMeasurement); }
private static Measurement GetMeasurement(Guid signalID) { MeasurementKey key = MeasurementKey.LookUpBySignalID(signalID); if (key.SignalID == Guid.Empty) { return(null); } Measurement measurement = new Measurement { Metadata = key.Metadata, }; return(measurement); }
// Creates an alarm event from the given alarm and measurement. private IMeasurement CreateAlarmEvent(Ticks timestamp, Alarm alarm) { IMeasurement alarmEvent = new Measurement() { Timestamp = timestamp, Value = (int)alarm.State }; if ((object)alarm.AssociatedMeasurementID != null) { Guid alarmEventID = alarm.AssociatedMeasurementID.GetValueOrDefault(); alarmEvent.Metadata = MeasurementKey.LookUpBySignalID(alarmEventID).Metadata; } return(alarmEvent); }
public async Task <IActionResult> OnGet(int?measurementKeyId) { if (measurementKeyId.HasValue) { MeasurementKey = await _measurementKeyData.GetById(measurementKeyId.Value); } else { MeasurementKey = new MeasurementKey(); } if (MeasurementKey == null) { RedirectToPage("../Error"); } return(Page()); }
private void m_timer_Elapsed(object sender, ElapsedEventArgs e) { List <IMeasurement> measurements = new List <IMeasurement>(); StringBuilder columnString = new StringBuilder(); int timestampColumn = GetColumnIndex("Timestamp"); int idColumn = GetColumnIndex("SignalID"); int valueColumn = GetColumnIndex("Value"); string commandString; IDbCommand command; IDataReader reader; foreach (string columnName in s_measurementColumns) { if (columnString.Length > 0) { columnString.Append(','); } columnString.Append(columnName); } commandString = string.Format("SELECT {0} FROM Measurement LIMIT {1},{2}", columnString, m_startingMeasurement, m_measurementsPerInput); command = m_connection.CreateCommand(); command.CommandText = commandString; using (reader = command.ExecuteReader()) { while (reader.Read()) { Ticks timeStamp = m_fakeTimestamps ? new Ticks(DateTime.UtcNow) : new Ticks(reader.GetInt64(timestampColumn)); MeasurementKey key = MeasurementKey.LookUpBySignalID(reader.GetGuid(idColumn)); if (key != MeasurementKey.Undefined) { measurements.Add(new Measurement { Key = key, Value = reader.GetDouble(valueColumn), Timestamp = timeStamp }); } } } OnNewMeasurements(measurements); m_startingMeasurement += m_measurementsPerInput; }
public void RefreshMetadata() { // Force a recalculation of input measurement keys so that system can appropriately update routing tables string setting; if (Settings.TryGetValue("inputMeasurementKeys", out setting)) { InputMeasurementKeys = ParseInputMeasurementKeys(DataSource, true, setting); } else { InputMeasurementKeys = new MeasurementKey[0]; } InputSourceIDs = InputSourceIDs; m_metadataRefreshOperation.RunOnceAsync(); }
/// <summary> /// Creates an instance of <see cref="App"/> class. /// </summary> public App() { AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal); m_errorLogger = new ErrorLogger(); m_defaultErrorText = m_errorLogger.ErrorTextMethod; m_errorLogger.ErrorTextMethod = ErrorText; m_errorLogger.ExitOnUnhandledException = false; m_errorLogger.HandleUnhandledException = true; m_errorLogger.LogToEmail = false; m_errorLogger.LogToEventLog = true; m_errorLogger.LogToFile = true; m_errorLogger.LogToScreenshot = true; m_errorLogger.LogToUI = true; m_errorLogger.Initialize(); m_title = AssemblyInfo.EntryAssembly.Title; // Setup default cache for measurement keys and associated Guid based signal ID's AdoDataConnection database = null; try { database = new AdoDataConnection(CommonFunctions.DefaultSettingsCategory); MeasurementKey.EstablishDefaultCache(database.Connection, database.AdapterType); } catch (Exception ex) { // First attempt to display a modal dialog will fail to block this // thread -- modal dialog displayed by the error logger will block now MessageBox.Show(ex.Message); // Log and display error, then exit application - manager must connect to database to continue m_errorLogger.Log(new InvalidOperationException(string.Format("{0} cannot connect to database: {1}", m_title, ex.Message), ex), true); } finally { if (database != null) { database.Dispose(); } } IsolatedStorageManager.WriteToIsolatedStorage("MirrorMode", false); }
/// <summary> /// Looks up measurement key from point tag. /// </summary> /// <param name="pointTag">Point tag to lookup.</param> /// <param name="source">Source metadata.</param> /// <returns>Measurement key from source metadata.</returns> /// <remarks> /// This function uses the <see cref="DataTable.Select(string)"/> function which uses a linear /// search algorithm that can be slow for large data sets, it is recommended that any results /// for calls to this function be cached to improve performance. /// </remarks> internal static MeasurementKey KeyFromTag(this string pointTag, DataSet source) { DataRow record = pointTag.MetadataRecordFromTag(source); if ((object)record == null) { return(MeasurementKey.Undefined); } try { return(MeasurementKey.LookUpOrCreate(record["SignalID"].ToNonNullString(Guid.Empty.ToString()).ConvertToType <Guid>(), record["ID"].ToString())); } catch { return(MeasurementKey.Undefined); } }
// Gets a measurement key based on a token which // may be either a signal ID or measurement key. private MeasurementKey GetKey(string token) { Guid signalID; MeasurementKey key; if (Guid.TryParse(token, out signalID)) { // Defined using the measurement's GUID key = MeasurementKey.LookUpBySignalID(signalID); } else { // Defined using the measurement's key key = MeasurementKey.Parse(token); } return(key); }
private string GetDescription(MeasurementKey key, TableOperations <ActiveMeasurement> table) { ActiveMeasurement measurement = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()); string text = measurement.Description; string stopAt = measurement.PhasorType == 'I' ? "-I" : "-V"; if (!string.IsNullOrWhiteSpace(text)) { int charLocation = text.IndexOf(stopAt, StringComparison.Ordinal); if (charLocation > 0) { return(text.Substring(0, charLocation)); } } return(string.Empty); }
// Lookup signal type for given measurement key private SignalType LookupSignalType(MeasurementKey key) { try { DataRow[] filteredRows = DataSource.Tables["ActiveMeasurements"].Select(string.Format("ID = '{0}'", key)); if (filteredRows.Length > 0) { return((SignalType)Enum.Parse(typeof(SignalType), filteredRows[0]["SignalType"].ToString(), true)); } } catch (Exception ex) { OnProcessException(new InvalidOperationException(string.Format("Failed to lookup signal type for measurement {0}: {1}", key, ex.Message), ex)); } return(SignalType.NONE); }
private Measurement GetMeasurement(Guid signalID) { DataRow[] rows = DataSource.Tables["ActiveMeasurements"].Select($"SignalID = '{signalID}'"); if (!rows.Any()) { return(null); } Measurement measurement = new Measurement { Key = MeasurementKey.LookUpBySignalID(signalID), TagName = rows[0]["PointTag"].ToString(), Adder = Convert.ToDouble(rows[0]["Adder"]), Multiplier = Convert.ToDouble(rows[0]["Multiplier"]) }; return(measurement); }
/// <summary> /// Gets the minimum retention time for the signal identified by the given key. /// </summary> /// <param name="key">The key that identifies the signal.</param> TimeSpan IMapper.GetMinimumRetentionTime(MeasurementKey key) { TimeSpan retentionTime; if (key == MeasurementKey.Undefined) { return(TimeSpan.Zero); } lock (m_minimumRetentionLock) { if (m_minimumRetentionTimes.TryGetValue(key, out retentionTime)) { return(retentionTime); } } return(TimeSpan.Zero); }
/// <summary> /// Get <see cref="MeasurementMetadata"/> for specified <see cref="SignalKind"/>. /// </summary> /// <param name="lookup">A lookup table by signal reference.</param> /// <param name="type"><see cref="SignalKind"/> to request signal reference for.</param> /// <param name="index">Index <see cref="SignalKind"/> to request signal reference for.</param> /// <param name="count">Number of signals defined for this <see cref="SignalKind"/>.</param> /// <returns>The MeasurementMetadata for a given <see cref="SignalKind"/>. Null if it does not exist.</returns> public MeasurementMetadata GetMetadata(Dictionary <string, MeasurementKey> lookup, SignalKind type, int index, int count) { // Clear the cache if the lookup dictionary has changed. // Since the instance of Lookup is effectively readonly as implemented in PhasorMeasurementMapper // a simple reference check is all that is needed. If it could be modified, this would likely be a // concurrent dictionary instead. if (m_keyLookupObject != lookup) { Array.Clear(m_generatedMeasurementKeyCache, 0, m_generatedMeasurementKeyCache.Length); m_keyLookupObject = lookup; } // Gets the cache for the supplied SignalKind int typeIndex = (int)type; MeasurementKey[] keyArray = m_generatedMeasurementKeyCache[typeIndex]; // If this SignalKind is null, create the sub array and generate all item lookups, also, rebuild // if the count is not the same. This could be because a new config frame was received. if ((object)keyArray == null || keyArray.Length != count) { keyArray = new MeasurementKey[count]; m_generatedMeasurementKeyCache[typeIndex] = keyArray; for (int x = 0; x < count; x++) { string signalReference = GetSignalReference(type, x, count); MeasurementKey key; if (lookup.TryGetValue(signalReference, out key)) { keyArray[x] = key; } else { keyArray[x] = MeasurementKey.Undefined; } } } return(keyArray[index]?.Metadata); }
/// <summary> /// Read historian data from server. /// </summary> /// <param name="connection">openHistorian connection.</param> /// <param name="startTime">Start time of query.</param> /// <param name="stopTime">Stop time of query.</param> /// <param name="measurementIDs">Comma separated list of measurement IDs to query - or <c>null</c> for all available points.</param> /// <param name="resolution">Resolution for data query.</param> /// <returns>Enumeration of <see cref="IMeasurement"/> values read for time range.</returns> /// <example> /// <code> /// using (var connection = new Connection("127.0.0.1", "PPA")) /// foreach(var measurement in GetHistorianData(connection, DateTime.UtcNow.AddMinutes(-1.0D), DateTime.UtcNow)) /// Console.WriteLine("{0}:{1} @ {2} = {3}, quality: {4}", measurement.Key.Source, measurement.Key.ID, measurement.Timestamp, measurement.Value, measurement.StateFlags); /// </code> /// </example> public static IEnumerable <IMeasurement> GetHistorianData(Connection connection, DateTime startTime, DateTime stopTime, string measurementIDs = null, Resolution resolution = Resolution.Full) { SeekFilterBase <HistorianKey> timeFilter; MatchFilterBase <HistorianKey, HistorianValue> pointFilter = null; HistorianKey key = new HistorianKey(); HistorianValue value = new HistorianValue(); // Set data scan resolution if (resolution == Resolution.Full) { timeFilter = TimestampSeekFilter.CreateFromRange <HistorianKey>(startTime, stopTime); } else { timeFilter = TimestampSeekFilter.CreateFromIntervalData <HistorianKey>(startTime, stopTime, resolution.GetInterval(), new TimeSpan(TimeSpan.TicksPerMillisecond)); } // Setup point ID selections if (!string.IsNullOrEmpty(measurementIDs)) { pointFilter = PointIdMatchFilter.CreateFromList <HistorianKey, HistorianValue>(measurementIDs.Split(',').Select(ulong.Parse)); } // Start stream reader for the provided time window and selected points using (Database database = connection.OpenDatabase()) { TreeStream <HistorianKey, HistorianValue> stream = database.Read(SortedTreeEngineReaderOptions.Default, timeFilter, pointFilter); while (stream.Read(key, value)) { yield return new Measurement() { Metadata = MeasurementKey.LookUpOrCreate(connection.InstanceName, (uint)key.PointID).Metadata, Timestamp = key.TimestampAsDate, Value = value.AsSingle, StateFlags = (MeasurementStateFlags)value.Value3 } } ; } }
/// <summary> /// Sets the minimum retention time for the signal identified by the given key. /// </summary> /// <param name="key">The key that identifies the signal.</param> /// <param name="retentionTime">The minimum amount of time measurements are to be retained by the signal buffer.</param> void IMapper.SetMinimumRetentionTime(MeasurementKey key, TimeSpan retentionTime) { if (key == MeasurementKey.Undefined) { return; } lock (m_minimumRetentionLock) { if (retentionTime != TimeSpan.Zero) { m_minimumRetentionTimes[key] = retentionTime; } else { m_minimumRetentionTimes.Remove(key); } } UpdateRetentionTimes(); FixSignalBuffers(); }
/// <summary> /// Queries a signal buffer for the full collection of measurements over the given sample window. /// </summary> /// <param name="key">The key that identifies the signal to be queried.</param> /// <param name="frameTime">The time of the frame relative to which the sample window is defined.</param> /// <param name="window">The sample window that defines the range of time to be queried from the buffer.</param> /// <param name="resamplingStrategy">The strategy to use for alignment of data to the sample rate of the window.</param> /// <returns>The full collection of measurements for the given signal in the given sample window relative to the given frame time.</returns> public List <IMeasurement> GetMeasurements(MeasurementKey key, Ticks frameTime, SampleWindow window, ResamplingStrategy resamplingStrategy) { SignalBuffer signalBuffer; if (!m_signalBuffers.TryGetValue(key, out signalBuffer)) { return(null); } switch (resamplingStrategy) { default: case ResamplingStrategy.NearestMeasurement: return(window.AlignNearest(signalBuffer, frameTime)); case ResamplingStrategy.FillMissingData: return(window.AlignFill(signalBuffer, frameTime)); case ResamplingStrategy.None: return(window.AlignNone(signalBuffer, frameTime)); } }
private void HandleSendMeasurementsCommand(ClientConnection connection, byte[] buffer, int startIndex, int length) { int index = startIndex; if (length - index < 4) { throw new Exception("Not enough bytes in buffer to parse measurement count"); } int count = BigEndian.ToInt32(buffer, index); index += sizeof(int); if (length - index < count * 36) { throw new Exception("Not enough bytes in buffer to parse all measurements"); } List <IMeasurement> measurements = new List <IMeasurement>(count); for (int i = 0; i < count; i++) { Guid signalID = buffer.ToRfcGuid(index); index += 16; DateTime timestamp = new DateTime(BigEndian.ToInt64(buffer, index)); index += sizeof(long); double value = BigEndian.ToDouble(buffer, index); index += sizeof(double); MeasurementStateFlags stateFlags = (MeasurementStateFlags)BigEndian.ToInt32(buffer, index); index += sizeof(int); measurements.Add(new Measurement() { Metadata = MeasurementKey.LookUpBySignalID(signalID).Metadata, Timestamp = timestamp, Value = value, StateFlags = stateFlags }); } OnNewMeasurements(measurements); }
/// <summary> /// Initializes <see cref="PhasorInputOscillationDetector" />. /// </summary> public override void Initialize() { InputCount = 4; OutputCount = Outputs.Length; base.Initialize(); MeasurementKey getMeasurementKey(SignalType signalType) => InputMeasurementKeys.Where((_, index) => InputMeasurementKeyTypes[index] == signalType).FirstOrDefault(); const string ErrorPrefix = "Angle and magnitude measurements for both a voltage and current phasor are required inputs. "; const string ErrorSuffix = " input measurement is missing, cannot initialize adapter."; // Validate input contains voltage and current phase angle / magnitude measurement keys m_voltageMagnitude = getMeasurementKey(SignalType.VPHM) ?? throw new InvalidOperationException(ErrorPrefix + "Voltage magnitude" + ErrorSuffix); m_voltageAngle = getMeasurementKey(SignalType.VPHA) ?? throw new InvalidOperationException(ErrorPrefix + "Voltage angle" + ErrorSuffix); m_currentMagnitude = getMeasurementKey(SignalType.IPHM) ?? throw new InvalidOperationException(ErrorPrefix + "Current magnitude" + ErrorSuffix); m_currentAngle = getMeasurementKey(SignalType.IPHA) ?? throw new InvalidOperationException(ErrorPrefix + "Current angle" + ErrorSuffix); // Make sure input measurement keys are in desired order InputMeasurementKeys = new[] { m_voltageMagnitude, m_voltageAngle, m_currentMagnitude, m_currentAngle }; // Provide algorithm with parameters as configured by adapter PseudoConfiguration configuration = new PseudoConfiguration { FramesPerSecond = FramesPerSecond, IsLineToNeutral = AdjustmentStrategy == VoltageAdjustmentStrategy.LineToNeutral }; m_detector.DetectorAPI = new PseudoDetectorAPI { Configuration = configuration }; m_detector.OutputMeasurements = OutputMeasurements; m_detector.FramesPerSecond = FramesPerSecond; m_detector.InputTypes = InputMeasurementKeyTypes; m_detector.Initialize(Name); }
private SignalType GetSignalType(MeasurementKey key, TableOperations <ActiveMeasurement> table) { ActiveMeasurement measurement = table.QueryRecordWhere("SignalID = {0}", key.SignalID.ToString()); if (measurement.SignalType == "IPHM") { return(SignalType.IPHM); } if (measurement.SignalType == "IPHA") { return(SignalType.IPHA); } if (measurement.SignalType == "VPHM") { return(SignalType.VPHM); } if (measurement.SignalType == "VPHA") { return(SignalType.VPHA); } return(SignalType.NONE); }
private void HistorianDataListener_DataExtracted(object sender, EventArgs <IList <IDataPoint> > e) { try { List <IMeasurement> measurements = new List <IMeasurement>(); foreach (IDataPoint dataPoint in e.Argument) { measurements.Add(new Measurement { Metadata = MeasurementKey.LookUpOrCreate(m_historianDataListener.ID, (uint)dataPoint.HistorianID).Metadata, Value = dataPoint.Value, Timestamp = dataPoint.Time }); } OnNewMeasurements(measurements); } catch (Exception ex) { OnProcessException(MessageLevel.Warning, ex); } }
/// <summary> /// Constructs a new <see cref="Measurement"/> given the specified parameters. /// </summary> /// <param name="id">Numeric ID of the new measurement.</param> /// <param name="source">Source name of the new measurement.</param> /// <param name="signalID"><see cref="Guid"/> based signal ID of the new measurement.</param> /// <param name="value">Value of the new measurement.</param> /// <param name="adder">Defined adder to apply to the new measurement.</param> /// <param name="multiplier">Defined multiplier to apply to the new measurement.</param> /// <param name="timestamp">Timestamp, in ticks, of the new measurement.</param> public Measurement(uint id, string source, Guid signalID, double value, double adder, double multiplier, Ticks timestamp) { m_id = id; m_source = source; m_key = new MeasurementKey(m_id, m_source); m_signalID = signalID; m_value = value; m_adder = adder; m_multiplier = multiplier; m_timestamp = timestamp; m_valueQualityIsGood = true; m_timestampQualityIsGood = true; }
public void RefreshMetadata() { // Force a recalculation of input measurement keys so that system can appropriately update routing tables string setting; if (Settings.TryGetValue("inputMeasurementKeys", out setting)) InputMeasurementKeys = ParseInputMeasurementKeys(DataSource, true, setting); else InputMeasurementKeys = new MeasurementKey[0]; InputSourceIDs = InputSourceIDs; m_metadataRefreshOperation.RunOnceAsync(); }
/// <summary> /// Gets runtime signal index for given <see cref="Guid"/> signal ID. /// </summary> /// <param name="key">The <see cref="MeasurementKey"/> used to lookup associated runtime signal index.</param> /// <returns>Runtime signal index for given <see cref="MeasurementKey"/> <paramref name="key"/>.</returns> public ushort GetSignalIndex(MeasurementKey key) { int value = m_signalIDCache[key.RuntimeID]; if (value < 0) return ushort.MaxValue; return (ushort)value; }
// Adds the given mapping to the key-variable map. private void AddMapping(MeasurementKey key, string alias) { if (m_variableNames.Contains(alias)) throw new ArgumentException(string.Format("Variable name is not unique: {0}", alias)); m_variableNames.Add(alias); m_keyMapping.Add(key, alias); }
// Add a measurement to the list of out of range measurements corresponding to the given key. private void AddOutOfRangeMeasurement(MeasurementKey key, IMeasurement measurement) { lock (m_outOfRangeMeasurements) { LinkedList<IMeasurement> outOfRangeList; if (!m_outOfRangeMeasurements.TryGetValue(key, out outOfRangeList)) { outOfRangeList = new LinkedList<IMeasurement>(); m_outOfRangeMeasurements.Add(key, outOfRangeList); } outOfRangeList.AddLast(measurement); } }
/// <summary> /// Initializes <see cref="SynchronizedClientSubscription"/>. /// </summary> public override void Initialize() { MeasurementKey[] inputMeasurementKeys; string setting; if (Settings.TryGetValue("inputMeasurementKeys", out setting)) { // IMPORTANT: The allowSelect argument of ParseInputMeasurementKeys must be null // in order to prevent SQL injection via the subscription filter expression inputMeasurementKeys = AdapterBase.ParseInputMeasurementKeys(DataSource, false, setting); m_requestedInputFilter = setting; // IMPORTANT: We need to remove the setting before calling base.Initialize() // or else we will still be subject to SQL injection Settings.Remove("inputMeasurementKeys"); } else { inputMeasurementKeys = new MeasurementKey[0]; m_requestedInputFilter = null; } base.Initialize(); // Set the InputMeasurementKeys and UsePrecisionTimer properties after calling // base.Initialize() so that the base class does not overwrite our settings InputMeasurementKeys = inputMeasurementKeys; UsePrecisionTimer = false; if (Settings.TryGetValue("bufferBlockRetransmissionTimeout", out setting)) m_bufferBlockRetransmissionTimeout = double.Parse(setting); else m_bufferBlockRetransmissionTimeout = 5.0D; if (Settings.TryGetValue("requestNaNValueFilter", out setting)) m_isNaNFiltered = m_parent.AllowNaNValueFilter && setting.ParseBoolean(); else m_isNaNFiltered = false; m_bufferBlockRetransmissionTimer = new Timer(); m_bufferBlockRetransmissionTimer.AutoReset = false; m_bufferBlockRetransmissionTimer.Interval = m_bufferBlockRetransmissionTimeout * 1000.0D; m_bufferBlockRetransmissionTimer.Elapsed += BufferBlockRetransmissionTimer_Elapsed; // Handle temporal session initialization if (this.TemporalConstraintIsDefined()) m_iaonSession = this.CreateTemporalSession(); }
/// <summary>Associates a new measurement ID with a tag, creating the new tag if needed.</summary> /// <remarks>Allows you to define "grouped" points so you can aggregate certain measurements.</remarks> /// <param name="key">A <see cref="MeasurementKey"/> to associate with the tag.</param> /// <param name="tag">A <see cref="String"/> to represent the key.</param> public void AddTaggedMeasurement(string tag, MeasurementKey key) { // Check for new tag if (!m_taggedMeasurements.ContainsKey(tag)) m_taggedMeasurements.Add(tag, new List<MeasurementKey>()); // Add measurement to tag's measurement list List<MeasurementKey> measurements = m_taggedMeasurements[tag]; if (measurements.BinarySearch(key) < 0) { measurements.Add(key); measurements.Sort(); } }
/// <summary>Retrieves the specified immediate temporal measurement, creating it if needed.</summary> /// <param name="key">A <see cref="MeasurementKey"/> object indicating the key to use.</param> /// <returns>A <see cref="TemporalMeasurement"/> object.</returns> public TemporalMeasurement Measurement(MeasurementKey key) { lock (m_measurements) { TemporalMeasurement value; if (!m_measurements.TryGetValue(key, out value)) { // Create new temporal measurement if it doesn't exist value = new TemporalMeasurement(key.ID, key.Source, double.NaN, m_parent.RealTime, m_parent.LagTime, m_parent.LeadTime); m_measurements.Add(key, value); } return value; } }
/// <summary> /// Intializes <see cref="AdapterBase"/>. /// </summary> public virtual void Initialize() { Initialized = false; Dictionary<string, string> settings = Settings; string setting; if (settings.TryGetValue("inputMeasurementKeys", out setting)) InputMeasurementKeys = AdapterBase.ParseInputMeasurementKeys(DataSource, setting); else InputMeasurementKeys = new MeasurementKey[0]; if (settings.TryGetValue("outputMeasurements", out setting)) OutputMeasurements = AdapterBase.ParseOutputMeasurements(DataSource, setting); if (settings.TryGetValue("measurementReportingInterval", out setting)) MeasurementReportingInterval = int.Parse(setting); else MeasurementReportingInterval = DefaultMeasurementReportingInterval; if (settings.TryGetValue("connectOnDemand", out setting)) AutoStart = !setting.ParseBoolean(); else AutoStart = true; string startTime, stopTime, parameters; bool startTimeDefined = settings.TryGetValue("startTimeConstraint", out startTime); bool stopTimeDefined = settings.TryGetValue("stopTimeConstraint", out stopTime); if (startTimeDefined || stopTimeDefined) { settings.TryGetValue("timeConstraintParameters", out parameters); SetTemporalConstraint(startTime, stopTime, parameters); } int processingInterval; if (settings.TryGetValue("processingInterval", out setting) && !string.IsNullOrWhiteSpace(setting) && int.TryParse(setting, out processingInterval)) ProcessingInterval = processingInterval; if (settings.TryGetValue("dependencyTimeout", out setting)) m_dependencyTimeout = Ticks.FromSeconds(double.Parse(setting)); else m_dependencyTimeout = Ticks.PerSecond / 30L; }
/// <summary> /// Initializes <see cref="ActionAdapterBase"/>. /// </summary> public virtual void Initialize() { Initialized = false; Dictionary<string, string> settings = Settings; const string errorMessage = "{0} is missing from Settings - Example: framesPerSecond=30; lagTime=3; leadTime=1"; string setting; // Load required parameters if (!settings.TryGetValue("framesPerSecond", out setting)) throw new ArgumentException(string.Format(errorMessage, "framesPerSecond")); base.FramesPerSecond = int.Parse(setting); if (!settings.TryGetValue("lagTime", out setting)) throw new ArgumentException(string.Format(errorMessage, "lagTime")); base.LagTime = double.Parse(setting); if (!settings.TryGetValue("leadTime", out setting)) throw new ArgumentException(string.Format(errorMessage, "leadTime")); base.LeadTime = double.Parse(setting); // Load optional parameters if (settings.TryGetValue("usePrecisionTimer", out setting)) UsePrecisionTimer = setting.ParseBoolean(); if (settings.TryGetValue("useLocalClockAsRealTime", out setting)) UseLocalClockAsRealTime = setting.ParseBoolean(); if (settings.TryGetValue("ignoreBadTimestamps", out setting)) IgnoreBadTimestamps = setting.ParseBoolean(); if (settings.TryGetValue("allowSortsByArrival", out setting)) AllowSortsByArrival = setting.ParseBoolean(); if (settings.TryGetValue("inputMeasurementKeys", out setting)) InputMeasurementKeys = AdapterBase.ParseInputMeasurementKeys(DataSource, true, setting); else InputMeasurementKeys = new MeasurementKey[0]; if (settings.TryGetValue("outputMeasurements", out setting)) OutputMeasurements = AdapterBase.ParseOutputMeasurements(DataSource, true, setting); if (settings.TryGetValue("minimumMeasurementsToUse", out setting)) MinimumMeasurementsToUse = int.Parse(setting); if (settings.TryGetValue("timeResolution", out setting)) TimeResolution = long.Parse(setting); if (settings.TryGetValue("allowPreemptivePublishing", out setting)) AllowPreemptivePublishing = setting.ParseBoolean(); if (settings.TryGetValue("performTimestampReasonabilityCheck", out setting)) PerformTimestampReasonabilityCheck = setting.ParseBoolean(); if (settings.TryGetValue("processByReceivedTimestamp", out setting)) ProcessByReceivedTimestamp = setting.ParseBoolean(); if (settings.TryGetValue("trackPublishedTimestamp", out setting)) TrackPublishedTimestamp = setting.ParseBoolean(); if (settings.TryGetValue("maximumPublicationTimeout", out setting)) MaximumPublicationTimeout = int.Parse(setting); if (settings.TryGetValue("downsamplingMethod", out setting)) { DownsamplingMethod method; if (Enum.TryParse(setting, true, out method)) { DownsamplingMethod = method; } else { OnStatusMessage("WARNING: No down-sampling method labeled \"{0}\" exists, \"LastReceived\" method was selected.", setting); DownsamplingMethod = DownsamplingMethod.LastReceived; } } if (settings.TryGetValue("inputSourceIDs", out setting)) InputSourceIDs = setting.Split(','); if (settings.TryGetValue("outputSourceIDs", out setting)) OutputSourceIDs = setting.Split(','); if (settings.TryGetValue("connectOnDemand", out setting)) AutoStart = !setting.ParseBoolean(); else AutoStart = true; if (settings.TryGetValue("respectInputDemands", out setting)) RespectInputDemands = setting.ParseBoolean(); else RespectInputDemands = false; if (settings.TryGetValue("respectOutputDemands", out setting)) RespectOutputDemands = setting.ParseBoolean(); else RespectOutputDemands = true; string startTime, stopTime, parameters; bool startTimeDefined = settings.TryGetValue("startTimeConstraint", out startTime); bool stopTimeDefined = settings.TryGetValue("stopTimeConstraint", out stopTime); if (startTimeDefined || stopTimeDefined) { settings.TryGetValue("timeConstraintParameters", out parameters); SetTemporalConstraint(startTime, stopTime, parameters); } int processingInterval; if (settings.TryGetValue("processingInterval", out setting) && !string.IsNullOrWhiteSpace(setting) && int.TryParse(setting, out processingInterval)) ProcessingInterval = processingInterval; }
public void UpdateConfiguration() { const int labelLength = 16; Dictionary<string, int> signalCellIndexes = new Dictionary<string, int>(); ConfigurationCell cell; SignalReference signal; SignalReference[] signals; MeasurementKey measurementKey; PhasorType phasorType; AnalogType analogType; char phaseType; string label; int order; uint scale; double offset; // Define a protocol independent configuration frame m_baseConfigurationFrame = new ConfigurationFrame(m_idCode, DateTime.UtcNow.Ticks, (ushort)base.FramesPerSecond); // Define configuration cells (i.e., PMU's that will appear in outgoing data stream) foreach (DataRow deviceRow in DataSource.Tables["OutputStreams"].Select(string.Format("StreamID={0}", ID))) { try { // Create a new configuration cell cell = new ConfigurationCell(m_baseConfigurationFrame, ushort.Parse(deviceRow["ID"].ToString()), deviceRow["IsVirtual"].ToNonNullString("false").ParseBoolean()); // The base class defaults to floating-point, polar values, derived classes can change cell.PhasorDataFormat = DataFormat.FloatingPoint; cell.PhasorCoordinateFormat = CoordinateFormat.Polar; cell.FrequencyDataFormat = DataFormat.FloatingPoint; cell.AnalogDataFormat = DataFormat.FloatingPoint; cell.IDLabel = deviceRow["Acronym"].ToString().Trim(); cell.StationName = deviceRow["Name"].ToString().TruncateRight(cell.MaximumStationNameLength).Trim(); // Define all the phasors configured for this device foreach (DataRow phasorRow in DataSource.Tables["OutputStreamPhasors"].Select(string.Format("DeviceID={0}", cell.IDCode), "Order")) { order = int.Parse(phasorRow["Order"].ToNonNullString("0")); label = phasorRow["Label"].ToNonNullString("Phasor " + order).Trim().RemoveDuplicateWhiteSpace().TruncateRight(labelLength - 4); phasorType = phasorRow["PhasorType"].ToNonNullString("V").Trim().ToUpper().StartsWith("V") ? PhasorType.Voltage : PhasorType.Current; phaseType = phasorRow["PhaseType"].ToNonNullString("+").Trim().ToUpper()[0]; cell.PhasorDefinitions.Add( new PhasorDefinition( cell, GeneratePhasorLabel(label, phaseType, phasorType), phasorType, null)); } // Add frequency definition label = string.Format("{0} Freq", cell.IDLabel.TruncateRight(labelLength - 5)).Trim(); cell.FrequencyDefinition = new FrequencyDefinition(cell, label); // Optionally define all the analogs configured for this device if (DataSource.Tables.Contains("OutputStreamAnalogs")) { foreach (DataRow analogRow in DataSource.Tables["OutputStreamAnalogs"].Select(string.Format("DeviceID={0}", cell.IDCode), "Order")) { order = int.Parse(analogRow["Order"].ToNonNullString("0")); label = analogRow["Label"].ToNonNullString("Analog " + order).Trim().RemoveDuplicateWhiteSpace().TruncateRight(labelLength); scale = uint.Parse(analogRow["Scale"].ToNonNullString("1")); offset = double.Parse(analogRow["Offset"].ToNonNullString("0.0")); analogType = analogRow["AnalogType"].ToNonNullString("SinglePointOnWave").ConvertToType<AnalogType>(); cell.AnalogDefinitions.Add( new AnalogDefinition( cell, label, scale, offset, analogType)); } } // Optionally define all the digitals configured for this device if (DataSource.Tables.Contains("OutputStreamDigitals")) { foreach (DataRow digitalRow in DataSource.Tables["OutputStreamDigitals"].Select(string.Format("DeviceID={0}", cell.IDCode), "Order")) { order = int.Parse(digitalRow["Order"].ToNonNullString("0")); label = digitalRow["Label"].ToNonNullString("Digital " + order).Trim().RemoveDuplicateWhiteSpace().TruncateRight(labelLength); cell.DigitalDefinitions.Add( new DigitalDefinition( cell, label)); } } m_baseConfigurationFrame.Cells.Add(cell); } catch (Exception ex) { OnProcessException(new InvalidOperationException(string.Format("Failed to define output stream device \"{0}\" due to exception: {1}", deviceRow["Acronym"].ToString().Trim(), ex.Message), ex)); } } OnStatusMessage("Defined {0} output stream devices...", m_baseConfigurationFrame.Cells.Count); // Create a new signal reference dictionary indexed on measurement keys m_signalReferences = new Dictionary<MeasurementKey, SignalReference[]>(); // Define measurement to signals cross reference dictionary foreach (DataRow measurementRow in DataSource.Tables["OutputStreamMeasurements"].Select(string.Format("StreamID={0}", ID))) { try { // Create a new signal reference signal = new SignalReference(measurementRow["SignalReference"].ToString()); // Lookup cell index by acronym - doing this work upfront will save a huge amount // of work during primary measurement sorting if (!signalCellIndexes.TryGetValue(signal.Acronym, out signal.CellIndex)) { // We cache these indicies locally to speed up initialization as we'll be // requesting them for the same devices over and over signal.CellIndex = m_configurationFrame.Cells.IndexOfIDLabel(signal.Acronym); signalCellIndexes.Add(signal.Acronym, signal.CellIndex); } // Define measurement key measurementKey = new MeasurementKey(uint.Parse(measurementRow["PointID"].ToString()), measurementRow["Historian"].ToString()); // It is possible, but not as common, that a measurement will have multiple destinations // within an outgoing data stream frame, hence the following if (m_signalReferences.TryGetValue(measurementKey, out signals)) { // Add a new signal to existing collection List<SignalReference> signalList = new List<SignalReference>(signals); signalList.Add(signal); m_signalReferences[measurementKey] = signalList.ToArray(); } else { // Add new signal to new collection signals = new SignalReference[1]; signals[0] = signal; m_signalReferences.Add(measurementKey, signals); } } catch (Exception ex) { OnProcessException(new InvalidOperationException(string.Format("Failed to associate measurement key to signal reference \"{0}\" due to exception: {1}", measurementRow["SignalReference"].ToString().Trim(), ex.Message), ex)); } } // Assign action adapter input measurement keys InputMeasurementKeys = m_signalReferences.Keys.ToArray(); // Create a new protocol specific configuration frame m_configurationFrame = CreateNewConfigurationFrame(m_baseConfigurationFrame); // Cache new protocol specific configuration frame CacheConfigurationFrame(m_configurationFrame); }
/// <summary> /// Prepares the adapter to query data for the points that have been requested for connect on demand. The adapter will /// look up PI tag names and start up the thread to start the timers and threads necessary to run. /// </summary> /// <param name="keys"></param> private void HandleNewMeasurementsRequest(MeasurementKey[] keys) { if (!IsConnected) AttemptConnection(); StopGettingData(); if (keys != null && keys.Length > 0) { var query = from row in DataSource.Tables["ActiveMeasurements"].AsEnumerable() from key in keys where row["ID"].ToString().Split(':')[1] == key.ID.ToString() && row["PROTOCOL"].ToString() == "PI" select new { Key = key, AlternateTag = row["ALTERNATETAG"].ToString(), PointTag = row["POINTTAG"].ToString() }; StringBuilder whereClause = new StringBuilder(); foreach (var result in query) { string tagname = result.PointTag; if (!String.IsNullOrWhiteSpace(result.AlternateTag)) tagname = result.AlternateTag; if (!m_tagKeyMap.ContainsKey(tagname)) m_tagKeyMap.Add(tagname, result.Key); if (whereClause.Length > 0) whereClause.Append(" OR "); whereClause.Append(string.Format("tag='{0}'", tagname)); } // Store this filtering string for when the PointList is created during query m_tagFilter = whereClause.ToString(); ThreadPool.QueueUserWorkItem(StartGettingData); } }
/// <summary> /// Initializes <see cref="SerializableMeasurement"/> from the specified binary image. /// </summary> /// <param name="buffer">Buffer containing binary image to parse.</param> /// <param name="startIndex">0-based starting index in the <paramref name="buffer"/> to start parsing.</param> /// <param name="length">Valid number of bytes within <paramref name="buffer"/> from <paramref name="startIndex"/>.</param> /// <returns>The number of bytes used for initialization in the <paramref name="buffer"/> (i.e., the number of bytes parsed).</returns> /// <exception cref="InvalidOperationException">Not enough buffer available to deserialize measurement.</exception> /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is null.</exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="startIndex"/> or <paramref name="length"/> is less than 0 -or- /// <paramref name="startIndex"/> and <paramref name="length"/> will exceed <paramref name="buffer"/> length. /// </exception> 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); }
/// <summary> /// Initializes <see cref="UnsynchronizedClientSubscription"/>. /// </summary> public override void Initialize() { MeasurementKey[] inputMeasurementKeys; string setting; if (Settings.TryGetValue("inputMeasurementKeys", out setting)) { // IMPORTANT: The allowSelect argument of ParseInputMeasurementKeys must be null // in order to prevent SQL injection via the subscription filter expression inputMeasurementKeys = ParseInputMeasurementKeys(DataSource, false, setting); m_requestedInputFilter = setting; // IMPORTANT: We need to remove the setting before calling base.Initialize() // or else we will still be subject to SQL injection Settings.Remove("inputMeasurementKeys"); } else { inputMeasurementKeys = new MeasurementKey[0]; m_requestedInputFilter = null; } base.Initialize(); // Set the InputMeasurementKeys property after calling base.Initialize() // so that the base class does not overwrite our setting InputMeasurementKeys = inputMeasurementKeys; if (Settings.TryGetValue("publishInterval", out setting)) m_publishInterval = int.Parse(setting); else m_publishInterval = -1; if (Settings.TryGetValue("includeTime", out setting)) m_includeTime = setting.ParseBoolean(); else m_includeTime = true; if (Settings.TryGetValue("useMillisecondResolution", out setting)) m_useMillisecondResolution = setting.ParseBoolean(); else m_useMillisecondResolution = false; if (Settings.TryGetValue("requestNaNValueFilter", out setting)) m_isNaNFiltered = m_parent.AllowNaNValueFilter && setting.ParseBoolean(); else m_isNaNFiltered = false; if (Settings.TryGetValue("bufferBlockRetransmissionTimeout", out setting)) m_bufferBlockRetransmissionTimeout = double.Parse(setting); else m_bufferBlockRetransmissionTimeout = 5.0D; if (m_parent.UseBaseTimeOffsets && m_includeTime) { m_baseTimeRotationTimer = Common.TimerScheduler.CreateTimer(m_useMillisecondResolution ? 60000 : 420000); m_baseTimeRotationTimer.AutoReset = true; m_baseTimeRotationTimer.Elapsed += BaseTimeRotationTimer_Elapsed; } m_bufferBlockRetransmissionTimer = Common.TimerScheduler.CreateTimer((int)(m_bufferBlockRetransmissionTimeout * 1000.0D)); m_bufferBlockRetransmissionTimer.AutoReset = false; m_bufferBlockRetransmissionTimer.Elapsed += BufferBlockRetransmissionTimer_Elapsed; // Handle temporal session initialization if (this.TemporalConstraintIsDefined()) m_iaonSession = this.CreateTemporalSession(); }
// Gets a measurement key based on a token which // may be either a signal ID or measurement key. private MeasurementKey GetKey(string token) { MeasurementKey undefined; Guid signalId; MeasurementKey key; if (Guid.TryParse(token, out signalId)) { // Defined using the measurement's GUID undefined = MeasurementKey.Undefined; key = new MeasurementKey(signalId, undefined.ID, undefined.Source); } else { // Defined using the measurement's key key = MeasurementKey.Parse(token); } return key; }
/// <summary> /// Determines if specified measurement key is defined in <see cref="InputMeasurementKeys"/>. /// </summary> /// <param name="item">Primary key of measurement to find.</param> /// <returns>true if specified measurement key is defined in <see cref="InputMeasurementKeys"/>.</returns> public virtual bool IsInputMeasurement(MeasurementKey item) { return (m_inputMeasurementKeysHash.BinarySearch(item) >= 0); }
/// <summary> /// Intializes <see cref="AdapterBase"/>. /// </summary> public virtual void Initialize() { Initialized = false; Dictionary<string, string> settings = Settings; string setting; if (settings.TryGetValue("inputMeasurementKeys", out setting)) InputMeasurementKeys = AdapterBase.ParseInputMeasurementKeys(DataSource, setting); else InputMeasurementKeys = new MeasurementKey[0]; if (settings.TryGetValue("outputMeasurements", out setting)) OutputMeasurements = AdapterBase.ParseOutputMeasurements(DataSource, setting); if (settings.TryGetValue("measurementReportingInterval", out setting)) MeasurementReportingInterval = int.Parse(setting); else MeasurementReportingInterval = DefaultMeasurementReportingInterval; if (settings.TryGetValue("connectOnDemand", out setting)) AutoStart = !setting.ParseBoolean(); else AutoStart = true; string startTime, stopTime, parameters; bool startTimeDefined = settings.TryGetValue("startTimeConstraint", out startTime); bool stopTimeDefined = settings.TryGetValue("stopTimeConstraint", out stopTime); if (startTimeDefined || stopTimeDefined) { settings.TryGetValue("timeConstraintParameters", out parameters); SetTemporalConstraint(startTime, stopTime, parameters); } int processingInterval; if (settings.TryGetValue("processingInterval", out setting) && !setting.IsNullOrWhiteSpace() && int.TryParse(setting, out processingInterval)) ProcessingInterval = processingInterval; // // Establish any defined external event wait handles needed for inter-adapter synchronization // if (settings.TryGetValue("waitHandleNames", out setting) && !setting.IsNullOrWhiteSpace()) // m_externalEventHandles = setting.Split(',').Select(GetExternalEventHandle).ToArray(); int waitHandleTimeout; if (settings.TryGetValue("waitHandleTimeout", out setting) && !setting.IsNullOrWhiteSpace() && int.TryParse(setting, out waitHandleTimeout)) m_externalEventTimeout = waitHandleTimeout; else m_externalEventTimeout = 33; }
/// <summary> /// Initializes <see cref="CompactMeasurement"/> from the specified binary image. /// </summary> /// <param name="buffer">Buffer containing binary image to parse.</param> /// <param name="startIndex">0-based starting index in the <paramref name="buffer"/> to start parsing.</param> /// <param name="length">Valid number of bytes within <paramref name="buffer"/> from <paramref name="startIndex"/>.</param> /// <returns>The number of bytes used for initialization in the <paramref name="buffer"/> (i.e., the number of bytes parsed).</returns> /// <exception cref="InvalidOperationException">Not enough buffer available to deserialize measurement.</exception> /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is null.</exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="startIndex"/> or <paramref name="length"/> is less than 0 -or- /// <paramref name="startIndex"/> and <paramref name="length"/> will exceed <paramref name="buffer"/> length. /// </exception> public int ParseBinaryImage(byte[] buffer, int startIndex, int length) { buffer.ValidateParameters(startIndex, length); if (length < 1) throw new InvalidOperationException("Not enough buffer available to deserialize measurement."); // Decode flags CompactMeasurementStateFlags flags = (CompactMeasurementStateFlags)buffer[startIndex]; StateFlags = flags.MapToFullFlags(); m_timeIndex = (flags & CompactMeasurementStateFlags.TimeIndex) > 0 ? 1 : 0; m_usingBaseTimeOffset = (flags & CompactMeasurementStateFlags.BaseTimeOffset) > 0; int index = startIndex + 1; // Decode runtime ID ushort id = EndianOrder.BigEndian.ToUInt16(buffer, index); index += 2; // Restore signal identification Tuple<Guid, string, uint> tuple; if (m_signalIndexCache.Reference.TryGetValue(id, out tuple)) { ID = tuple.Item1; Key = new MeasurementKey(tuple.Item1, tuple.Item3, tuple.Item2); } else throw new InvalidOperationException("Failed to find associated signal identification for runtime ID " + id); // Decode value Value = EndianOrder.BigEndian.ToSingle(buffer, index); index += 4; if (m_includeTime) { if (m_usingBaseTimeOffset) { long baseTimeOffset = m_baseTimeOffsets[m_timeIndex]; if (m_useMillisecondResolution) { // Decode 2-byte millisecond offset timestamp if (baseTimeOffset > 0) Timestamp = baseTimeOffset + EndianOrder.BigEndian.ToUInt16(buffer, index) * Ticks.PerMillisecond; index += 2; } else { // Decode 4-byte tick offset timestamp if (baseTimeOffset > 0) Timestamp = baseTimeOffset + EndianOrder.BigEndian.ToUInt32(buffer, index); index += 4; } } else { // Decode 8-byte full fidelity timestamp Timestamp = EndianOrder.BigEndian.ToInt64(buffer, index); index += 8; } } return (index - startIndex); }
/// <summary> /// Determines if specified measurement key is defined in <see cref="InputMeasurementKeys"/>. /// </summary> /// <param name="item">Primary key of measurement to find.</param> /// <returns>true if specified measurement key is defined in <see cref="InputMeasurementKeys"/>.</returns> public virtual bool IsInputMeasurement(MeasurementKey item) { if (m_inputMeasurementKeysHash != null) return (m_inputMeasurementKeysHash.BinarySearch(item) >= 0); // If no input measurements are defined we must assume user wants to accept all measurements - yikes! return true; }
/// <summary> /// Get a collection of out-of-range <see cref="IMeasurement"/>s with the given key. /// </summary> /// <param name="key">The <see cref="MeasurementKey"/> corresponding to the desired measurements.</param> /// <returns>A collection of out-of-range <see cref="IMeasurement"/>s.</returns> public ICollection<IMeasurement> GetOutOfRangeMeasurements(MeasurementKey key) { lock (m_outOfRangeMeasurements) { PurgeOldMeasurements(key); return new LinkedList<IMeasurement>(m_outOfRangeMeasurements[key]); } }
// Purge old, out-of-range measurements with the given key. private void PurgeOldMeasurements(MeasurementKey key) { lock (m_outOfRangeMeasurements) { LinkedList<IMeasurement> measurements = m_outOfRangeMeasurements[key]; bool donePurging = false; // Purge old measurements to prevent redundant warnings. while (measurements.Count > 0 && !donePurging) { IMeasurement measurement = measurements.First.Value; Ticks diff = base.RealTime - measurement.Timestamp; if (diff >= base.LagTicks + m_timeToPurge) measurements.RemoveFirst(); else donePurging = true; } } }
private void HandleNewMeasurementsRequest(MeasurementKey[] Keys) { OnStatusMessage("Received request for {0} keys...", new object[] { Keys.Count() }); if (!IsConnected) AttemptConnection(); var query = from row in DataSource.Tables["ActiveMeasurements"].AsEnumerable() from key in Keys where row["ID"].ToString().Split(':')[1] == key.ID.ToString() select new { Key = key, AlternateTag = row["ALTERNATETAG"].ToString(), PointTag = row["POINTTAG"].ToString() }; StringBuilder tagFilter = new StringBuilder(); foreach (var row in query) { string tagname = row.PointTag; if (!String.IsNullOrWhiteSpace(row.AlternateTag)) tagname = row.AlternateTag; if (!m_tagKeyMap.ContainsKey(tagname)) { m_tagKeyMap.AddOrUpdate(tagname, row.Key, (k, v) => row.Key); } if (tagFilter.Length > 0) tagFilter.Append(" OR "); tagFilter.Append(string.Format("tag='{0}'", tagname)); } m_points = m_server.GetPoints(tagFilter.ToString()); // event pipes are only applicable if enabled in connection string and this is a real time session, not playback bool useEventPipes = m_useEventPipes && StartTimeConstraint == DateTime.MinValue && StopTimeConstraint == DateTime.MaxValue; if (useEventPipes) { try { if (m_pipe != null) ((_DEventPipeEvents_Event)m_pipe).OnNewValue -= (PISDK._DEventPipeEvents_OnNewValueEventHandler)PipeOnOnNewValue; m_pipe = m_points.Data.EventPipe; ((_DEventPipeEvents_Event)m_pipe).OnNewValue += (PISDK._DEventPipeEvents_OnNewValueEventHandler)PipeOnOnNewValue; } catch (ThreadAbortException) { throw; } catch (Exception e) { useEventPipes = false; // try to run with polling instead of event pipes; OnProcessException(e); } } if (!useEventPipes) { // warn that we are going to use a different configuration here... if (m_useEventPipes) OnStatusMessage("WARNING: PI adapter switching from event pipes to polling due to error or start/stop time constraints."); // set up a new thread to do some long calls to PI and set up threads, timers, etc for polling StopGettingData(); ThreadPool.QueueUserWorkItem(StartGettingData, tagFilter); } m_useEventPipes = useEventPipes; }
/// <summary> /// Spawn routing tables recalculation. /// </summary> /// <param name="inputMeasurementKeysRestriction">Input measurement keys restriction.</param> /// <remarks> /// Set the <paramref name="inputMeasurementKeysRestriction"/> to null to use full adapter I/O routing demands. /// </remarks> public virtual void CalculateRoutingTables(MeasurementKey[] inputMeasurementKeysRestriction) { try { m_inputMeasurementKeysRestriction = inputMeasurementKeysRestriction; m_calculateRoutingTablesOperation.RunOnceAsync(); } catch (Exception ex) { // Process exception for logging OnProcessException(new InvalidOperationException("Failed to queue routing table calculation: " + ex.Message, ex)); } }