/// <summary> /// Creates a new <see cref="ConfigurationCreator"/>. /// </summary> public ConfigurationCreator() { InitializeComponent(); m_configurationFrame = new ConfigurationFrame((ushort)0, (Ticks)0, (ushort)30); listBoxDevices.ItemsSource = m_configurationFrame.Cells; listBoxDevices.SelectedValuePath = "@IDCode"; }
/// <summary> /// Creates a new <see cref="ConfigurationCell"/> from specified parameters. /// </summary> /// <param name="parent">The reference to parent <see cref="ConfigurationFrame"/> of this <see cref="ConfigurationCell"/>.</param> /// <param name="idCode">The numeric ID code for this <see cref="ConfigurationCell"/>.</param> /// <param name="isVirtual">Assigns flag that determines if this <see cref="ConfigurationCell"/> is virtual.</param> public ConfigurationCell(ConfigurationFrame parent, ushort idCode, bool isVirtual) : base(parent, idCode, int.MaxValue, int.MaxValue, int.MaxValue) { m_signalReferences = new Dictionary<SignalType, string[]>(); m_analogDataFormat = DataFormat.FloatingPoint; m_frequencyDataFormat = DataFormat.FloatingPoint; m_phasorDataFormat = DataFormat.FloatingPoint; m_phasorCoordinateFormat = CoordinateFormat.Polar; m_isVirtual = isVirtual; }
/// <summary> /// Creates a new protocol specific <see cref="IConfigurationFrame"/> based on provided protocol independent <paramref name="baseConfigurationFrame"/>. /// </summary> /// <param name="baseConfigurationFrame">Protocol independent <paramref name="IConfigurationFrame"/>.</param> /// <returns>A new protocol specific <see cref="IConfigurationFrame"/>.</returns> /// <remarks> /// Derived classes should notify consumers of change in configuration if system is active when /// new configuration frame is created if outgoing protocol allows such a notfication. /// </remarks> protected abstract IConfigurationFrame CreateNewConfigurationFrame(ConfigurationFrame baseConfigurationFrame);
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); }