/// <summary> /// Creates a new <see cref="ConnectionParameters"/>. /// </summary> public ConnectionParameters() { m_timeOffset = Common.DefaultTimeOffset; m_frameRate = Common.DefaultFrameRate; m_nominalFrequency = Common.DefaultNominalFrequency; m_stationName = Common.DefaultStationName; }
/// <summary> /// Creates a new <see cref="ConnectionParameters"/> from serialization parameters. /// </summary> /// <param name="info">The <see cref="SerializationInfo"/> with populated with data.</param> /// <param name="context">The source <see cref="StreamingContext"/> for this deserialization.</param> protected ConnectionParameters(SerializationInfo info, StreamingContext context) { // Deserialize connection parameters m_timeOffset = info.GetInt64("timeOffset"); m_frameRate = info.GetUInt16("frameRate"); m_nominalFrequency = (LineFrequency)info.GetValue("nominalFrequency", typeof(LineFrequency)); m_stationName = info.GetString("stationName"); }
/// <summary> /// Creates a new <see cref="ConnectionParameters"/> from serialization parameters. /// </summary> /// <param name="info">The <see cref="SerializationInfo"/> with populated with data.</param> /// <param name="context">The source <see cref="StreamingContext"/> for this deserialization.</param> protected ConnectionParameters(SerializationInfo info, StreamingContext context) { // Deserialize connection parameters m_timeOffset = info.GetOrDefault("timeOffset", Common.DefaultTimeOffset); m_frameRate = info.GetOrDefault("frameRate", Common.DefaultFrameRate); m_nominalFrequency = info.GetOrDefault("nominalFrequency", Common.DefaultNominalFrequency); m_stationName = info.GetOrDefault("stationName", Common.DefaultStationName); }
/// <summary> /// Creates a new <see cref="ConfigurationCellBase"/> from specified parameters. /// </summary> /// <param name="parent">The reference to parent <see cref="IConfigurationFrame"/> of this <see cref="ConfigurationCellBase"/>.</param> /// <param name="idCode">The numeric ID code for this <see cref="ConfigurationCellBase"/>.</param> /// <param name="maximumPhasors">Sets the maximum number of phasors for the <see cref="PhasorDefinitions"/> collection.</param> /// <param name="maximumAnalogs">Sets the maximum number of phasors for the <see cref="AnalogDefinitions"/> collection.</param> /// <param name="maximumDigitals">Sets the maximum number of phasors for the <see cref="DigitalDefinitions"/> collection.</param> protected ConfigurationCellBase(IConfigurationFrame parent, ushort idCode, int maximumPhasors, int maximumAnalogs, int maximumDigitals) : base(parent, idCode) { m_nominalFrequency = LineFrequency.Hz60; // Defaulting to 60Hz // We convert maximum counts to last valid indicies (count - 1): m_phasorDefinitions = new PhasorDefinitionCollection(maximumPhasors - 1); m_analogDefinitions = new AnalogDefinitionCollection(maximumAnalogs - 1); m_digitalDefinitions = new DigitalDefinitionCollection(maximumDigitals - 1); }
/// <summary> /// Creates a new <see cref="ConfigurationCellBase"/> from serialization parameters. /// </summary> /// <param name="info">The <see cref="SerializationInfo"/> with populated with data.</param> /// <param name="context">The source <see cref="StreamingContext"/> for this deserialization.</param> protected ConfigurationCellBase(SerializationInfo info, StreamingContext context) : base(info, context) { // Deserialize configuration cell values StationName = info.GetString("stationName"); IDLabel = info.GetString("idLabel"); m_phasorDefinitions = (PhasorDefinitionCollection)info.GetValue("phasorDefinitions", typeof(PhasorDefinitionCollection)); m_frequencyDefinition = (IFrequencyDefinition)info.GetValue("frequencyDefinition", typeof(IFrequencyDefinition)); m_analogDefinitions = (AnalogDefinitionCollection)info.GetValue("analogDefinitions", typeof(AnalogDefinitionCollection)); m_digitalDefinitions = (DigitalDefinitionCollection)info.GetValue("digitalDefinitions", typeof(DigitalDefinitionCollection)); m_nominalFrequency = (LineFrequency)info.GetValue("nominalFrequency", typeof(LineFrequency)); m_revisionCount = info.GetUInt16("revisionCount"); }
/// <summary> /// Creates a new <see cref="ConfigurationFrame"/> from specified parameters. /// </summary> /// <param name="idCode">The ID code of this <see cref="ConfigurationFrame"/>.</param> /// <param name="timestamp">The exact timestamp, in <see cref="Ticks"/>, of the data represented by this <see cref="ConfigurationFrame"/>.</param> /// <param name="frameRate">The defined frame rate of this <see cref="ConfigurationFrame"/>.</param> /// <param name="nominalFrequency">The nominal <see cref="LineFrequency"/> of this <see cref="ConfigurationFrame"/>.</param> /// <param name="timeOffset">The time offset of F-NET device in <see cref="Ticks"/>.</param> /// <param name="stationName">The station name of the F-NET device.</param> /// <remarks> /// This constructor is used by a consumer to generate an F-NET configuration frame. /// </remarks> public ConfigurationFrame(ushort idCode, Ticks timestamp, ushort frameRate, LineFrequency nominalFrequency, Ticks timeOffset, string stationName) : base(idCode, new ConfigurationCellCollection(), timestamp, frameRate) { ConfigurationCell configCell = new ConfigurationCell(this, nominalFrequency, timeOffset); // FNet protocol sends data for one device Cells.Add(configCell); // Assign station name configCell.StationName = string.IsNullOrEmpty(stationName) ? $"F-NET Unit-{idCode}" : stationName; // Add a single frequency definition configCell.FrequencyDefinition = new FrequencyDefinition(configCell, "Line frequency"); // Add a single phasor definition configCell.PhasorDefinitions.Add(new PhasorDefinition(configCell, "120V Phasor", PhasorType.Voltage, null)); }
/// <summary> /// Creates a new <see cref="ConfigurationFrame"/> from specified parameters. /// </summary> /// <param name="idCode">The ID code of this <see cref="ConfigurationFrame"/>.</param> /// <param name="timestamp">The exact timestamp, in <see cref="Ticks"/>, of the data represented by this <see cref="ConfigurationFrame"/>.</param> /// <param name="frameRate">The defined frame rate of this <see cref="ConfigurationFrame"/>.</param> /// <param name="nominalFrequency">The nominal <see cref="LineFrequency"/> of this <see cref="ConfigurationFrame"/>.</param> /// <param name="timeOffset">The time offset of F-NET device in <see cref="Ticks"/>.</param> /// <param name="stationName">The station name of the F-NET device.</param> /// <remarks> /// This constructor is used by a consumer to generate an F-NET configuration frame. /// </remarks> public ConfigurationFrame(ushort idCode, Ticks timestamp, ushort frameRate, LineFrequency nominalFrequency, Ticks timeOffset, string stationName) : base(idCode, new ConfigurationCellCollection(), timestamp, frameRate) { ConfigurationCell configCell = new ConfigurationCell(this, nominalFrequency, timeOffset); // FNet protocol sends data for one device Cells.Add(configCell); // Assign station name if (string.IsNullOrEmpty(stationName)) configCell.StationName = "F-NET Unit-" + idCode; else configCell.StationName = stationName; // Add a single frequency definition configCell.FrequencyDefinition = new FrequencyDefinition(configCell, "Line frequency"); // Add a single phasor definition configCell.PhasorDefinitions.Add(new PhasorDefinition(configCell, "120V Phasor", PhasorType.Voltage, null)); }
/// <summary> /// Creates a new <see cref="ConfigurationCell"/> from specified parameters. /// </summary> /// <param name="parent">The reference to parent <see cref="ConfigurationFrame1"/> of this <see cref="ConfigurationCell"/>.</param> /// <param name="idCode">The numeric ID code for this <see cref="ConfigurationCell"/>.</param> /// <param name="nominalFrequency">The nominal <see cref="LineFrequency"/> of the <see cref="FrequencyDefinition"/> of this <see cref="ConfigurationCell"/>.</param> public ConfigurationCell(ConfigurationFrame1 parent, ushort idCode, LineFrequency nominalFrequency) : this(parent) { IDCode = idCode; NominalFrequency = nominalFrequency; }
/// <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="nominalFrequency">The nominal <see cref="LineFrequency"/> of the <see cref="FrequencyDefinition"/> of this <see cref="ConfigurationCell"/>.</param> public ConfigurationCell(ConfigurationFrame parent, ushort idCode, LineFrequency nominalFrequency) : this(parent) { IDCode = idCode; NominalFrequency = nominalFrequency; }
/// <summary> /// Creates a new <see cref="FrameParser"/>. /// </summary> /// <param name="checkSumValidationFrameTypes">Frame types that should perform check-sum validation; default to <see cref="GSF.PhasorProtocols.CheckSumValidationFrameTypes.AllFrames"/></param> /// <param name="trustHeaderLength">Determines if header lengths should be trusted over parsed byte count.</param> /// <param name="frameRate">The defined frame rate of this <see cref="ConfigurationFrame"/>.</param> /// <param name="nominalFrequency">The nominal <see cref="LineFrequency"/> of this <see cref="ConfigurationFrame"/>.</param> /// <param name="timeOffset">The time offset of F-NET device in <see cref="Ticks"/>.</param> /// <param name="stationName">The station name of the F-NET device.</param> public FrameParser(CheckSumValidationFrameTypes checkSumValidationFrameTypes = CheckSumValidationFrameTypes.AllFrames, bool trustHeaderLength = true, ushort frameRate = Common.DefaultFrameRate, LineFrequency nominalFrequency = Common.DefaultNominalFrequency, long timeOffset = Common.DefaultTimeOffset, string stationName = Common.DefaultStationName) : base(checkSumValidationFrameTypes, trustHeaderLength) { // Initialize protocol synchronization bytes for this frame parser base.ProtocolSyncBytes = new[] { Common.StartByte }; FrameRate = frameRate; NominalFrequency = nominalFrequency; TimeOffset = timeOffset; StationName = stationName; }
private int m_numberOfSatellites = 1; // We'll initially assume synchronization is good until told otherwise #endregion #region [ Constructors ] /// <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="nominalFrequency">The nominal <see cref="LineFrequency"/> of the <see cref="FrequencyDefinition"/> of this <see cref="ConfigurationCell"/>.</param> /// <param name="timeOffset">The time offset of F-NET device in <see cref="Ticks"/>.</param> internal ConfigurationCell(ConfigurationFrame parent, LineFrequency nominalFrequency, Ticks timeOffset) : base(parent, parent.IDCode, Common.MaximumPhasorValues, Common.MaximumAnalogValues, Common.MaximumDigitalValues) { NominalFrequency = nominalFrequency; m_timeOffset = timeOffset; }
public static ConfigurationFrame Parse(string configFile, ShowMessageFunc showMessage) { string[] rows = File.ReadAllLines(configFile); Dictionary <string, string> configSettings = rows .Select(row => row.Split('=')) .ToDictionary(key => key[0], value => value[1], StringComparer.OrdinalIgnoreCase); // Fixed for now LineFrequency nominalFrequency = LineFrequency.Hz60; // Load server name setting string serverName = configSettings["IPAddr"]; // Load ID code setting if (!ushort.TryParse(configSettings["IdCode"], out ushort idCode)) { idCode = DefaultIDCode; } // Load frame rate setting if (!ushort.TryParse(configSettings["DataRate"], out ushort frameRate)) { frameRate = DefaultFrameRate; } // With an ID code, frame rate and server name, there's enough info to create a config frame ConfigurationFrame configFrame = new(idCode, frameRate, serverName); // Load all output PMUs int index = -1; while (configSettings.TryGetValue($"PmuId{++index}", out string setting) && ushort.TryParse(setting, out idCode)) { string name = configSettings[$"PmuStn{index}"]; if (string.IsNullOrWhiteSpace(name)) { continue; } // With a name and an ID code, there's enough info to create a config cell representing the PMU ConfigurationCell configCell = new(configFrame, name, idCode) { NominalFrequency = nominalFrequency, }; name = "VaChan"; PhasorType phasorType = PhasorType.Voltage; char phase = 'A'; string description = $"{configCell.StationName} phase {phase} {phasorType.ToString().ToLowerInvariant()} phasor"; configCell.PhasorDefinitions.Add(new PhasorDefinition(configCell, name, description, phasorType, phase)); name = "VbChan"; phasorType = PhasorType.Voltage; phase = 'B'; description = $"{configCell.StationName} phase {phase} {phasorType.ToString().ToLowerInvariant()} phasor"; configCell.PhasorDefinitions.Add(new PhasorDefinition(configCell, name, description, phasorType, phase)); name = "VcChan"; phasorType = PhasorType.Voltage; phase = 'C'; description = $"{configCell.StationName} phase {phase} {phasorType.ToString().ToLowerInvariant()} phasor"; configCell.PhasorDefinitions.Add(new PhasorDefinition(configCell, name, description, phasorType, phase)); name = "IaChan"; phasorType = PhasorType.Current; phase = 'A'; description = $"{configCell.StationName} phase {phase} {phasorType.ToString().ToLowerInvariant()} phasor"; configCell.PhasorDefinitions.Add(new PhasorDefinition(configCell, name, description, phasorType, phase)); name = "IbChan"; phasorType = PhasorType.Current; phase = 'B'; description = $"{configCell.StationName} phase {phase} {phasorType.ToString().ToLowerInvariant()} phasor"; configCell.PhasorDefinitions.Add(new PhasorDefinition(configCell, name, description, phasorType, phase)); name = "IcChan"; phasorType = PhasorType.Current; phase = 'C'; description = $"{configCell.StationName} phase {phase} {phasorType.ToString().ToLowerInvariant()} phasor"; configCell.PhasorDefinitions.Add(new PhasorDefinition(configCell, name, description, phasorType, phase)); name = "InChan"; phasorType = PhasorType.Current; phase = 'N'; description = $"{configCell.StationName} phase {phase} {phasorType.ToString().ToLowerInvariant()} phasor"; configCell.PhasorDefinitions.Add(new PhasorDefinition(configCell, name, description, phasorType, phase)); configFrame.Cells.Add(configCell); } // Get connection details configured for APP PDC configFrame.TransportProtocol = DefaultTransportProtocol; if (!ushort.TryParse(configSettings["PortTCP"], out ushort port)) { port = DefaultPort; } //if (!ushort.TryParse(configSettings["PortUDP"], out ushort dataPort)) // dataPort = DefaultDataPort; // Setup MultiProtocolFrameParser style connection string Dictionary <string, string> getTcpSettings(bool commandChannel = false) { // Use of simple "protocol" key in commandChannel and separation of // server/port keys are required to create a proper "PmuConnection" // file that can be successfully parsed by the PMU Connection Tester return(new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase) { [commandChannel ? "protocol": nameof(TransportProtocol)] = nameof(TransportProtocol.Tcp), ["server"] = IPAddressToken, ["port"] = $"{port}", ["isListener"] = "false", ["interface"] = "0.0.0.0" }); } Dictionary <string, string> settings = configFrame.Settings; settings[nameof(PhasorProtocol)] = nameof(PhasorProtocol.IEEEC37_118V1); foreach (KeyValuePair <string, string> pair in getTcpSettings()) { settings[pair.Key] = pair.Value; } // Save device IP configuration Dictionary <string, string> deviceIPs = configFrame.DeviceIPs; deviceIPs[serverName] = serverName; configFrame.TargetDeviceIP = serverName; return(configFrame); }
/// <summary> /// Initializes <see cref="PhasorDataConcentratorBase"/>. /// </summary> public override void Initialize() { base.Initialize(); Dictionary<string, string> settings = Settings; string setting, commandChannel; // Load required parameters m_idCode = ushort.Parse(settings["IDCode"]); // Load optional parameters settings.TryGetValue("commandChannel", out commandChannel); if (settings.TryGetValue("autoPublishConfigFrame", out setting)) m_autoPublishConfigurationFrame = setting.ParseBoolean(); else m_autoPublishConfigurationFrame = !string.IsNullOrEmpty(commandChannel); if (settings.TryGetValue("autoStartDataChannel", out setting)) m_autoStartDataChannel = setting.ParseBoolean(); else m_autoStartDataChannel = true; if (settings.TryGetValue("nominalFrequency", out setting)) m_nominalFrequency = (LineFrequency)int.Parse(setting); else m_nominalFrequency = LineFrequency.Hz60; // Initialize data channel this.DataChannel = new UdpServer(ConnectionString); // Initialize command channel if defined if (!string.IsNullOrEmpty(commandChannel)) this.CommandChannel = new TcpServer(commandChannel); else this.CommandChannel = null; // Create the configuration frame UpdateConfiguration(); }
/// <summary> /// Creates a new <see cref="ConfigurationCell3"/> from specified parameters. /// </summary> /// <param name="parent">The reference to parent <see cref="ConfigurationFrame1"/> of this <see cref="ConfigurationCell3"/>.</param> /// <param name="idCode">The numeric ID code for this <see cref="ConfigurationCell3"/>.</param> /// <param name="nominalFrequency">The nominal <see cref="LineFrequency"/> of the <see cref="FrequencyDefinition"/> of this <see cref="ConfigurationCell3"/>.</param> public ConfigurationCell3(ConfigurationFrame1 parent, ushort idCode, LineFrequency nominalFrequency) //FIXME: Does this need to use config frame 3? : this(parent) { IDCode = idCode; NominalFrequency = nominalFrequency; }
// Static Methods /// <summary> /// Creates a new IEC 61850-90-5 (i.e., IEEE C37.118) <see cref="ConfigurationFrame"/> based on provided protocol independent <paramref name="baseConfigurationFrame"/>. /// </summary> /// <param name="baseConfigurationFrame">Protocol independent <see cref="GSF.PhasorProtocols.Anonymous.ConfigurationFrame"/>.</param> /// <param name="timeBase">Timebase to use for fraction second resolution.</param> /// <param name="nominalFrequency">The nominal <see cref="LineFrequency"/> to use for the new <see cref="ConfigurationFrame"/></param>. /// <returns>A new IEEE C37.118 <see cref="ConfigurationFrame"/>.</returns> public static ConfigurationFrame CreateConfigurationFrame(GSF.PhasorProtocols.Anonymous.ConfigurationFrame baseConfigurationFrame, uint timeBase, LineFrequency nominalFrequency) { ConfigurationCell newCell; uint maskValue; // Create a new IEEE C37.118 configuration frame 2 using base configuration ConfigurationFrame configurationFrame = new ConfigurationFrame(timeBase, baseConfigurationFrame.IDCode, DateTime.UtcNow.Ticks, baseConfigurationFrame.FrameRate); foreach (GSF.PhasorProtocols.Anonymous.ConfigurationCell baseCell in baseConfigurationFrame.Cells) { // Create a new IEEE C37.118 configuration cell (i.e., a PMU configuration) newCell = new ConfigurationCell(configurationFrame, baseCell.IDCode, nominalFrequency); // Update other cell level attributes newCell.StationName = baseCell.StationName; newCell.IDLabel = baseCell.IDLabel; newCell.PhasorDataFormat = baseCell.PhasorDataFormat; newCell.PhasorCoordinateFormat = baseCell.PhasorCoordinateFormat; newCell.FrequencyDataFormat = baseCell.FrequencyDataFormat; newCell.AnalogDataFormat = baseCell.AnalogDataFormat; // Add phasor definitions foreach (IPhasorDefinition phasorDefinition in baseCell.PhasorDefinitions) { newCell.PhasorDefinitions.Add(new PhasorDefinition(newCell, phasorDefinition.Label, phasorDefinition.ScalingValue, phasorDefinition.Offset, phasorDefinition.PhasorType, null)); } // Add frequency definition newCell.FrequencyDefinition = new FrequencyDefinition(newCell, baseCell.FrequencyDefinition.Label); // Add analog definitions foreach (IAnalogDefinition analogDefinition in baseCell.AnalogDefinitions) { newCell.AnalogDefinitions.Add(new AnalogDefinition(newCell, analogDefinition.Label, analogDefinition.ScalingValue, analogDefinition.Offset, analogDefinition.AnalogType)); } // Add digital definitions foreach (IDigitalDefinition digitalDefinition in baseCell.DigitalDefinitions) { // Attempt to derive user defined mask value if available DigitalDefinition anonymousDigitalDefinition = digitalDefinition as DigitalDefinition; if (anonymousDigitalDefinition != null) { maskValue = anonymousDigitalDefinition.MaskValue; } else { maskValue = 0U; } newCell.DigitalDefinitions.Add(new GSF.PhasorProtocols.IEC61850_90_5.DigitalDefinition(newCell, digitalDefinition.Label, maskValue.LowWord(), maskValue.HighWord())); } // Add new PMU configuration (cell) to protocol specific configuration frame configurationFrame.Cells.Add(newCell); } return(configurationFrame); }
/// <summary> /// Initializes <see cref="PhasorDataConcentratorBase"/>. /// </summary> public override void Initialize() { base.Initialize(); const string errorMessage = "{0} is missing from Settings - Example: IDCode=235; dataChannel={{Port=0; Clients=localhost:8800}}"; Dictionary<string, string> settings = Settings; string setting, dataChannel, commandChannel; // Load required parameters if (!settings.TryGetValue("IDCode", out setting)) throw new ArgumentException(string.Format(errorMessage, "IDCode")); m_idCode = ushort.Parse(setting); settings.TryGetValue("dataChannel", out dataChannel); settings.TryGetValue("commandChannel", out commandChannel); // Data channel and/or command channel must be defined if (string.IsNullOrEmpty(dataChannel) && string.IsNullOrEmpty(commandChannel)) throw new InvalidOperationException("A data channel or command channel must be defined for a concentrator."); // Load optional parameters if (settings.TryGetValue("autoPublishConfigFrame", out setting)) m_autoPublishConfigurationFrame = setting.ParseBoolean(); else m_autoPublishConfigurationFrame = string.IsNullOrEmpty(commandChannel); if (settings.TryGetValue("autoStartDataChannel", out setting)) m_autoStartDataChannel = setting.ParseBoolean(); else m_autoStartDataChannel = true; if (settings.TryGetValue("nominalFrequency", out setting)) m_nominalFrequency = (LineFrequency)int.Parse(setting); else m_nominalFrequency = LineFrequency.Hz60; if (settings.TryGetValue("dataFormat", out setting)) m_dataFormat = (DataFormat)Enum.Parse(typeof(DataFormat), setting, true); else m_dataFormat = DataFormat.FloatingPoint; if (settings.TryGetValue("coordinateFormat", out setting)) m_coordinateFormat = (CoordinateFormat)Enum.Parse(typeof(CoordinateFormat), setting, true); else m_coordinateFormat = CoordinateFormat.Polar; if (settings.TryGetValue("currentScalingValue", out setting)) { if (!uint.TryParse(setting, out m_currentScalingValue)) m_currentScalingValue = unchecked((uint)int.Parse(setting)); } else { m_currentScalingValue = 2423U; } if (settings.TryGetValue("voltageScalingValue", out setting)) { if (!uint.TryParse(setting, out m_voltageScalingValue)) m_voltageScalingValue = unchecked((uint)int.Parse(setting)); } else { m_voltageScalingValue = 2725785U; } if (settings.TryGetValue("analogScalingValue", out setting)) { if (!uint.TryParse(setting, out m_analogScalingValue)) m_analogScalingValue = unchecked((uint)int.Parse(setting)); } else { m_analogScalingValue = 1373291U; } if (settings.TryGetValue("digitalMaskValue", out setting)) { if (!uint.TryParse(setting, out m_digitalMaskValue)) m_digitalMaskValue = unchecked((uint)int.Parse(setting)); } else { m_digitalMaskValue = Word.MakeDoubleWord(0xFFFF, 0x0000); } if (settings.TryGetValue("processDataValidFlag", out setting)) m_processDataValidFlag = setting.ParseBoolean(); else m_processDataValidFlag = true; if (settings.TryGetValue("addPhaseLabelSuffix", out setting)) m_addPhaseLabelSuffix = setting.ParseBoolean(); else m_addPhaseLabelSuffix = true; if (settings.TryGetValue("replaceWithSpaceChar", out setting)) { if (!string.IsNullOrWhiteSpace(setting) && setting.Length > 0) m_replaceWithSpaceChar = setting[0]; else m_replaceWithSpaceChar = Char.MinValue; } else { m_replaceWithSpaceChar = Char.MinValue; } if (settings.TryGetValue("useAdjustedValue", out setting)) m_useAdjustedValue = Boolean.Parse(setting); else m_useAdjustedValue = true; // Initialize data channel if defined if (!string.IsNullOrEmpty(dataChannel)) this.DataChannel = new UdpServer(dataChannel); else this.DataChannel = null; // Initialize command channel if defined if (!string.IsNullOrEmpty(commandChannel)) this.CommandChannel = new TcpServer(commandChannel); else this.CommandChannel = null; // Create the configuration frame UpdateConfiguration(); // Register with the statistics engine StatisticsEngine.Register(this, "OutputStream", "OS"); StatisticsEngine.Calculated += (sender, args) => ResetLatencyCounters(); StatisticsEngine.Calculated += (sender, args) => ResetMeasurementsPerSecondCounters(); }
public static ConfigurationFrame Parse(string configFile, ShowMessageFunc showMessage) { XDocument config = XDocument.Load(configFile); // Load all "SettingsGroup" elements XElement[] settingsGroups = config.Descendants("SettingsGroup").ToArray(); // Load nominal frequency from "Globals" setting group string nominalFrequencySetting = settingsGroups .WhereAttribute("Type").Is("Globals") .Descendants("Setting") .WhereAttribute("Name").Is("Frequency") .GetValue(DefaultLineFrequency); LineFrequency nominalFrequency = nominalFrequencySetting.Equals("50") ? LineFrequency.Hz50 : LineFrequency.Hz60; // Get server gateway instances XElement[] serverGatewayInstances = settingsGroups .WhereAttribute("Type").Is("ServerGateway") .Descendants("Instance") .WhereAttribute("Type").Is("Server") .ToArray(); if (serverGatewayInstances.Length == 0) { throw new NullReferenceException($"No server gateway instances where defined in \"{Path.GetFileName(configFile)}\"."); } int enabledInstanceCount = serverGatewayInstances .Count(elem => elem.Descendants("Setting") .WhereAttribute("Name").Is("Enabled") .GetValue(false)); XElement serverGatewayInstance = null; if (enabledInstanceCount == 0) { if (showMessage($"No enabled server gateway instances where found in \"{Path.GetFileName(configFile)}\", do you want to load a disabled instance?", "No Enabled Server Gateways Found", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) { throw new NullReferenceException("Failed to load an enabled server gateway instance."); } serverGatewayInstance = serverGatewayInstances.FirstOrDefault(); } else { if (enabledInstanceCount > 1 && showMessage($"Found {enabledInstanceCount:N0} enabled server gateway instances in \"{Path.GetFileName(configFile)}\", do you want to load first enabled instance?", "Multiple Enabled Server Gateways Found", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) { throw new NullReferenceException("Failed to load an enabled server gateway instance."); } serverGatewayInstance = serverGatewayInstances .FirstOrDefault(elem => elem.Descendants("Setting") .WhereAttribute("Name").Is("Enabled") .GetValue(false)); } if (serverGatewayInstance is null) { throw new NullReferenceException("Failed to load any server gateway instance."); } // Load all "Setting" elements from server gateway instance XElement[] serverGatewaySettings = serverGatewayInstance .Descendants("Setting") .ToArray(); // Load server name setting string serverName = Path.GetFileNameWithoutExtension(configFile).GetCleanAcronym(); // Load ID code setting ushort idCode = serverGatewaySettings .WhereAttribute("Name").Is("ID") .GetValue(DefaultIDCode); // Load frame rate setting ushort frameRate = serverGatewaySettings .WhereAttribute("Name").Is("DataRate") .GetValue(DefaultFrameRate); // With an ID code, frame rate and server name, there's enough info to create a config frame ConfigurationFrame configFrame = new ConfigurationFrame(idCode, frameRate, serverName); // Load all output PMUs IEnumerable <XElement> pmus = serverGatewaySettings .WhereAttribute("Name").Is("OutputTags") .Descendants("PMU"); foreach (XElement pmu in pmus) { string name = pmu.Attribute("Name")?.Value; if (string.IsNullOrWhiteSpace(name)) { continue; } if (!ushort.TryParse(pmu.Attribute("ID")?.Value, out idCode)) { continue; } // With a name and an ID code, there's enough info to create a config cell representing the PMU ConfigurationCell configCell = new ConfigurationCell(configFrame, name, idCode) { NominalFrequency = nominalFrequency, }; // Load all PMU tags XElement[] tags = pmu.Descendants("Tag").ToArray(); // Load all phasor tags IEnumerable <XElement> phasors = tags .WhereAttribute("Type").Is("Phasor"); foreach (XElement phasor in phasors) { name = phasor.Attribute("Name")?.Value; if (string.IsNullOrWhiteSpace(name)) { continue; } string description = phasor.Attribute("Description")?.Value; string quantityType = phasor.Attribute("QuantityType")?.Value ?? DefaultPhasorType; PhasorType phasorType = quantityType.Equals("Current") ? PhasorType.Current : PhasorType.Voltage; string phaseSetting = phasor.Attribute("Phase")?.Value.Trim(); if (string.IsNullOrWhiteSpace(phaseSetting)) { phaseSetting = GuessPhase(phasor.Attribute("OriginalName")?.Value ?? name); } char phase = string.IsNullOrWhiteSpace(phaseSetting) ? DefaultPhase : TranslatePhase(phaseSetting[0]); if (string.IsNullOrWhiteSpace(description)) { description = $"{configCell.StationName} phase {phase} {phasorType.ToString().ToLowerInvariant()} phasor"; } configCell.PhasorDefinitions.Add(new PhasorDefinition(configCell, name, description, phasorType, phase)); } // Load all analog tags IEnumerable <XElement> analogs = tags .WhereAttribute("Type").Is("Analog"); foreach (XElement analog in analogs) { name = analog.Attribute("Name")?.Value; if (string.IsNullOrWhiteSpace(name)) { continue; } string description = analog.Attribute("Description")?.Value; if (string.IsNullOrWhiteSpace(description)) { description = $"{configCell.StationName} {name} analog value"; } configCell.AnalogDefinitions.Add(new AnalogDefinition(configCell, name, description)); } // Load all digital tags IEnumerable <XElement> digitals = tags .WhereAttribute("Type").Is("Digital"); foreach (XElement digital in digitals) { name = digital.Attribute("Name")?.Value; if (string.IsNullOrWhiteSpace(name)) { continue; } string description = digital.Attribute("Description")?.Value; if (string.IsNullOrWhiteSpace(description)) { description = $"{configCell.StationName} {name} digital value"; } configCell.DigitalDefinitions.Add(new DigitalDefinition(configCell, name, description)); } configFrame.Cells.Add(configCell); } // Get connection details configured for SEL PDC string transportProtocol = serverGatewaySettings .WhereAttribute("Name").Is("TransportProtocol") .GetValue(DefaultTransportProtocol) .ToUpperInvariant(); configFrame.TransportProtocol = transportProtocol; ushort commandPort = serverGatewaySettings .WhereAttribute("Name").Is("CommandPort") .GetValue(DefaultCommandPort); ushort dataPort = serverGatewaySettings .WhereAttribute("Name").Is("DataPort") .GetValue(DefaultDataPort); ushort port = serverGatewaySettings .WhereAttribute("Name").Is("Port") .GetValue(DefaultPort); bool multicastEnabled = serverGatewaySettings .WhereAttribute("Name").Is("MulticastEnabled") .GetValue(DefaultMulticastEnabled); string multicastGroup = serverGatewaySettings .WhereAttribute("Name").Is("MulticastGroup") .GetValue(DefaultMulticastGroup); // Setup MultiProtocolFrameParser style connection string Dictionary <string, string> getTcpSettings(bool commandChannel = false) { // Use of simple "protocol" key in commandChannel and separation of // server/port keys are required to create a proper "PmuConnection" // file that can be successfully parsed by the PMU Connection Tester return(new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase) { [commandChannel ? "protocol": nameof(TransportProtocol)] = nameof(TransportProtocol.Tcp), ["server"] = IPAddressToken, ["port"] = commandChannel ? $"{commandPort}" : $"{port}", ["isListener"] = "false", ["interface"] = "0.0.0.0" }); } Dictionary <string, string> settings = configFrame.Settings; settings[nameof(PhasorProtocol)] = nameof(PhasorProtocol.IEEEC37_118V1); if (transportProtocol == "TCP") { foreach (KeyValuePair <string, string> pair in getTcpSettings()) { settings[pair.Key] = pair.Value; } } else if (transportProtocol.StartsWith("UDP")) { settings[nameof(TransportProtocol)] = nameof(TransportProtocol.Udp); settings["localPort"] = $"{dataPort}"; settings["interface"] = "0.0.0.0"; switch (transportProtocol) { case "UDP_T": case "UDP_U": settings["commandChannel"] = getTcpSettings(true).JoinKeyValuePairs(); break; } if (multicastEnabled) { settings["server"] = multicastGroup; settings["remotePort"] = $"{commandPort}"; } } else { settings["error"] = "No valid connection protocol detected"; } // Save device IP configuration Dictionary <string, string> deviceIPs = configFrame.DeviceIPs; // Load "NetworkSettingsGroup" element from settings group XElement networkSettingsGroup = settingsGroups .WhereAttribute("Type").Is("NetworkSettingsGroup") .FirstOrDefault(); if (networkSettingsGroup is null) { deviceIPs["loopback"] = "127.0.0.1"; } else { string gatewayIP = networkSettingsGroup .Descendants("Setting") .WhereAttribute("Name").Is("Gateway") .GetValue(DefaultGatewayIP); // Get array of settings for each NIC interface IEnumerable <XElement[]> interfaceSettingsMap = networkSettingsGroup .Descendants("SettingsGroup") .WhereAttribute("Type").Is("NetworkGroup") .Descendants("Instance") .WhereAttribute("Type").Is("NetworkInterfaceCard") .Select(element => element.Descendants("Setting").ToArray()); foreach (XElement[] interfaceSettings in interfaceSettingsMap) { string name = interfaceSettings .WhereAttribute("Name").Is("Name") .GetValue(null); if (string.IsNullOrWhiteSpace(name)) { continue; } string ipAddress = interfaceSettings .WhereAttribute("Name").Is("IPAddress") .GetValue(null); if (string.IsNullOrWhiteSpace(ipAddress)) { continue; } deviceIPs[name] = ipAddress; } // Set the target device IP to the one that matches gateway IP the closest, // this is just a guess, user must select proper device IP configFrame.TargetDeviceIP = deviceIPs .ToDictionary(pair => pair.Key, pair => gatewayIP.OverlapCoefficient(pair.Value)) .Aggregate((x, y) => x.Value > y.Value ? x : y).Key; if (string.IsNullOrWhiteSpace(configFrame.TargetDeviceIP) && deviceIPs.Count > 0) { configFrame.TargetDeviceIP = deviceIPs.First().Key; } } return(configFrame); }
void IConfigurationFrame.SetNominalFrequency(LineFrequency value) { throw new NotImplementedException(); }
// Static Methods /// <summary> /// Creates a new IEC 61850-90-5 (i.e., IEEE C37.118) <see cref="ConfigurationFrame"/> based on provided protocol independent <paramref name="baseConfigurationFrame"/>. /// </summary> /// <param name="baseConfigurationFrame">Protocol independent <see cref="GSF.PhasorProtocols.Anonymous.ConfigurationFrame"/>.</param> /// <param name="timeBase">Timebase to use for fraction second resolution.</param> /// <param name="nominalFrequency">The nominal <see cref="LineFrequency"/> to use for the new <see cref="ConfigurationFrame"/></param>. /// <returns>A new IEEE C37.118 <see cref="ConfigurationFrame"/>.</returns> public static ConfigurationFrame CreateConfigurationFrame(GSF.PhasorProtocols.Anonymous.ConfigurationFrame baseConfigurationFrame, uint timeBase, LineFrequency nominalFrequency) { ConfigurationCell newCell; uint maskValue; // Create a new IEEE C37.118 configuration frame 2 using base configuration ConfigurationFrame configurationFrame = new ConfigurationFrame(timeBase, baseConfigurationFrame.IDCode, DateTime.UtcNow.Ticks, baseConfigurationFrame.FrameRate); foreach (GSF.PhasorProtocols.Anonymous.ConfigurationCell baseCell in baseConfigurationFrame.Cells) { // Create a new IEEE C37.118 configuration cell (i.e., a PMU configuration) newCell = new ConfigurationCell(configurationFrame, baseCell.IDCode, nominalFrequency); // Update other cell level attributes newCell.StationName = baseCell.StationName; newCell.IDLabel = baseCell.IDLabel; newCell.PhasorDataFormat = baseCell.PhasorDataFormat; newCell.PhasorCoordinateFormat = baseCell.PhasorCoordinateFormat; newCell.FrequencyDataFormat = baseCell.FrequencyDataFormat; newCell.AnalogDataFormat = baseCell.AnalogDataFormat; // Add phasor definitions foreach (IPhasorDefinition phasorDefinition in baseCell.PhasorDefinitions) { newCell.PhasorDefinitions.Add(new PhasorDefinition(newCell, phasorDefinition.Label, phasorDefinition.ScalingValue, phasorDefinition.Offset, phasorDefinition.PhasorType, null)); } // Add frequency definition newCell.FrequencyDefinition = new FrequencyDefinition(newCell, baseCell.FrequencyDefinition.Label); // Add analog definitions foreach (IAnalogDefinition analogDefinition in baseCell.AnalogDefinitions) { newCell.AnalogDefinitions.Add(new AnalogDefinition(newCell, analogDefinition.Label, analogDefinition.ScalingValue, analogDefinition.Offset, analogDefinition.AnalogType)); } // Add digital definitions foreach (IDigitalDefinition digitalDefinition in baseCell.DigitalDefinitions) { // Attempt to derive user defined mask value if available DigitalDefinition anonymousDigitalDefinition = digitalDefinition as DigitalDefinition; if (anonymousDigitalDefinition != null) maskValue = anonymousDigitalDefinition.MaskValue; else maskValue = 0U; newCell.DigitalDefinitions.Add(new GSF.PhasorProtocols.IEC61850_90_5.DigitalDefinition(newCell, digitalDefinition.Label, maskValue.LowWord(), maskValue.HighWord())); } // Add new PMU configuration (cell) to protocol specific configuration frame configurationFrame.Cells.Add(newCell); } return configurationFrame; }
private int m_numberOfSatellites = 1; // We'll initially assume synchronization is good until told otherwise #endregion #region [ Constructors ] /// <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="nominalFrequency">The nominal <see cref="LineFrequency"/> of the <see cref="FrequencyDefinition"/> of this <see cref="ConfigurationCell"/>.</param> /// <param name="timeOffset">The time offset of F-NET device in <see cref="Ticks"/>.</param> internal ConfigurationCell(ConfigurationFrame parent, LineFrequency nominalFrequency, Ticks timeOffset) : base(parent, parent.IDCode, Common.MaximumPhasorValues, Common.MaximumAnalogValues, Common.MaximumDigitalValues) { NominalFrequency = nominalFrequency; m_timeOffset = timeOffset; }