/// <summary> /// Parses the binary header image. /// </summary> /// <param name="buffer">Binary image to parse.</param> /// <param name="startIndex">Start index into <paramref name="buffer"/> to begin parsing.</param> /// <param name="length">Length of valid data within <paramref name="buffer"/>.</param> /// <returns>The length of the data that was parsed.</returns> protected override int ParseHeaderImage(byte[] buffer, int startIndex, int length) { // We already parsed the frame header, so we just skip past it... startIndex += CommonFrameHeader.FixedLength; // Parse on -line data format m_onlineDataFormatFlags = (OnlineDataFormatFlags)BigEndian.ToUInt16(buffer, startIndex); return(CommonFrameHeader.FixedLength + 2); }
/// <summary> /// Gets set of ONLINE data format flags based on the specified number of phasors. /// </summary> /// <param name="count">Total number phasors.</param> /// <returns>ONLINE data format flags based on the specified number of phasors.</returns> /// <remarks> /// This function always includes TimestampEnabled as part of the format flags. /// </remarks> public static OnlineDataFormatFlags GetFormatFlagsFromPhasorCount(int count) { OnlineDataFormatFlags flags = OnlineDataFormatFlags.TimestampEnabled; if (count > 1) { flags = flags | OnlineDataFormatFlags.Phasor2Enabled; } if (count > 2) { flags = flags | OnlineDataFormatFlags.Phasor3Enabled; } if (count > 3) { flags = flags | OnlineDataFormatFlags.Phasor4Enabled; } if (count > 4) { flags = flags | OnlineDataFormatFlags.Phasor5Enabled; } if (count > 5) { flags = flags | OnlineDataFormatFlags.Phasor6Enabled; } if (count > 6) { flags = flags | OnlineDataFormatFlags.Phasor7Enabled; } if (count > 7) { flags = flags | OnlineDataFormatFlags.Phasor8Enabled; } if (count > 8) { flags = flags | OnlineDataFormatFlags.Phasor9Enabled; } if (count > 9) { flags = flags | OnlineDataFormatFlags.Phasor10Enabled; } return(flags); }
/// <summary> /// Creates a new <see cref="ConfigurationFrame"/> 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 ConfigurationFrame(SerializationInfo info, StreamingContext context) : base(info, context) { // Deserialize configuration frame m_frameHeader = (CommonFrameHeader)info.GetValue("frameHeader", typeof(CommonFrameHeader)); m_onlineDataFormatFlags = (OnlineDataFormatFlags)info.GetValue("onlineDataFormatFlags", typeof(OnlineDataFormatFlags)); try { m_iniFile = new IniFile(info.GetString("configurationFileName")); } catch (SerializationException) { m_iniFile = null; } }
/// <summary> /// Creates a new <see cref="ConfigurationFrame"/>. /// </summary> /// <param name="onlineDataFormatFlags">Online data format flags to use in this Macrodyne <see cref="ConfigurationFrame"/>.</param> /// <param name="unitID">8 character unit ID to use in this Macrodyne <see cref="ConfigurationFrame"/>.</param> /// <param name="configurationFileName">INI configuration file name, if specified.</param> /// <param name="deviceLabel">INI section name.</param> /// <remarks> /// This constructor is used by a consumer to generate a Macrodyne configuration frame. /// </remarks> public ConfigurationFrame(OnlineDataFormatFlags onlineDataFormatFlags, string unitID, string configurationFileName = null, string deviceLabel = null) : base(0, new ConfigurationCellCollection(), 0, 0) { m_onlineDataFormatFlags = onlineDataFormatFlags; m_stationName = unitID; ConfigurationCell configCell = new ConfigurationCell(this, deviceLabel); // Macrodyne protocol sends data for one device Cells.Add(configCell); if (!string.IsNullOrEmpty(configurationFileName)) { m_iniFile = new IniFile(configurationFileName); } Refresh(); }
/// <summary> /// Creates a new <see cref="ConfigurationFrame"/>. /// </summary> /// <param name="onlineDataFormatFlags">Online data format flags to use in this Macrodyne <see cref="ConfigurationFrame"/>.</param> /// <param name="unitID">8 character unit ID to use in this Macrodyne <see cref="ConfigurationFrame"/>.</param> /// <remarks> /// This constructor is used by a consumer to generate a Macrodyne configuration frame. /// </remarks> public ConfigurationFrame(OnlineDataFormatFlags onlineDataFormatFlags, string unitID) : base(0, new ConfigurationCellCollection(), 0, 0) { m_onlineDataFormatFlags = onlineDataFormatFlags; ConfigurationCell configCell = new ConfigurationCell(this); // Assign station name configCell.StationName = unitID; // Add a single frequency definition configCell.FrequencyDefinition = new FrequencyDefinition(configCell, "Line frequency"); // Add phasors based on online format flags for (int i = 0; i < PhasorCount; i++) { configCell.PhasorDefinitions.Add(new PhasorDefinition(configCell, "Phasor " + (i + 1), PhasorType.Voltage, null)); } // Macrodyne protocol sends data for one device Cells.Add(configCell); }
/// <summary> /// Creates a new <see cref="ConfigurationCell"/> from specified parameters. /// </summary> /// <param name="parent">The parent <see cref="ConfigurationFrame"/> reference to use.</param> /// <param name="deviceLabel">INI section device label to use.</param> public ConfigurationCell(ConfigurationFrame parent, string deviceLabel = null) : base(parent, 0, Common.MaximumPhasorValues, Common.MaximumAnalogValues, Common.MaximumDigitalValues) { // Assign station name that came in from header frame StationName = parent.StationName; if (!string.IsNullOrEmpty(deviceLabel)) { SectionEntry = deviceLabel; } // Add a single frequency definition FrequencyDefinition = new FrequencyDefinition(this) { Label = "Line frequency" }; OnlineDataFormatFlags flags = parent.OnlineDataFormatFlags; PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 1", PhasorType.Voltage, null)); if ((flags & OnlineDataFormatFlags.Phasor2Enabled) == OnlineDataFormatFlags.Phasor2Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 2", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor3Enabled) == OnlineDataFormatFlags.Phasor3Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 3", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor4Enabled) == OnlineDataFormatFlags.Phasor4Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 4", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor5Enabled) == OnlineDataFormatFlags.Phasor5Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 5", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor6Enabled) == OnlineDataFormatFlags.Phasor6Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 6", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor7Enabled) == OnlineDataFormatFlags.Phasor7Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 7", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor8Enabled) == OnlineDataFormatFlags.Phasor8Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 8", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor9Enabled) == OnlineDataFormatFlags.Phasor9Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 9", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Phasor10Enabled) == OnlineDataFormatFlags.Phasor10Enabled) { PhasorDefinitions.Add(new PhasorDefinition(this, "Phasor 10", PhasorType.Voltage, null)); } if ((flags & OnlineDataFormatFlags.Digital1Enabled) == OnlineDataFormatFlags.Digital1Enabled) { DigitalDefinitions.Add(new DigitalDefinition(this, "Digital 1")); } if ((flags & OnlineDataFormatFlags.Digital2Enabled) == OnlineDataFormatFlags.Digital2Enabled) { DigitalDefinitions.Add(new DigitalDefinition(this, "Digital 2")); } }
/// <summary> /// Creates a new <see cref="ConfigurationFrame"/> 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 ConfigurationFrame(SerializationInfo info, StreamingContext context) : base(info, context) { // Deserialize configuration frame m_onlineDataFormatFlags = (OnlineDataFormatFlags)info.GetValue("onlineDataFormatFlags", typeof(OnlineDataFormatFlags)); }
/// <summary> /// Reload Macrodyne INI based configuration file. /// </summary> public void Refresh() { if ((object)m_iniFile == null) { return; } // The only time we need an access lock is when we reload the config file... lock (m_iniFile) { if (File.Exists(m_iniFile.FileName)) { ConfigurationCell pmuCell; int phasorCount, pmuCount, x, y; m_defaultPhasorV = new PhasorDefinition(null, 0, m_iniFile["DEFAULT", "PhasorV", DefaultVoltagePhasorEntry]); m_defaultPhasorI = new PhasorDefinition(null, 0, m_iniFile["DEFAULT", "PhasorI", DefaultCurrentPhasorEntry]); m_defaultFrequency = new FrequencyDefinition(null, m_iniFile["DEFAULT", "Frequency", DefaultFrequencyEntry]); FrameRate = ushort.Parse(m_iniFile["CONFIG", "SampleRate", "30"]); // We read all cells in the config file into their own configuration cell collection - cells parsed // from the configuration frame will be mapped to their associated config file cell by ID label // when the configuration cell is parsed from the configuration frame if (m_configurationFileCells == null) { m_configurationFileCells = new ConfigurationCellCollection(int.MaxValue); } m_configurationFileCells.Clear(); // Load phasor data for each section in config file... foreach (string section in m_iniFile.GetSectionNames()) { if (section.Length > 0) { // Make sure this is not a special section if (string.Compare(section, "DEFAULT", true) != 0 && string.Compare(section, "CONFIG", true) != 0) { // Create new PMU entry structure from config file settings... phasorCount = int.Parse(m_iniFile[section, "NumberPhasors", "0"]); // Check for PDC code int pdcID = int.Parse(m_iniFile[section, "PDC", "-1"]); if (pdcID == -1) { // No PDC entry exists, assume this is a PMU pmuCell = new ConfigurationCell(this); pmuCell.IDCode = ushort.Parse(m_iniFile[section, "PMU", Cells.Count.ToString()]); pmuCell.SectionEntry = section; // This will automatically assign ID label as first 4 digits of section pmuCell.StationName = m_iniFile[section, "Name", section]; pmuCell.PhasorDefinitions.Clear(); for (x = 0; x < phasorCount; x++) { pmuCell.PhasorDefinitions.Add(new PhasorDefinition(pmuCell, x + 1, m_iniFile[section, "Phasor" + (x + 1), DefaultVoltagePhasorEntry])); } pmuCell.FrequencyDefinition = new FrequencyDefinition(pmuCell, m_iniFile[section, "Frequency", DefaultFrequencyEntry]); m_configurationFileCells.Add(pmuCell); } else { // This is a PDC, need to define one virtual entry for each PMU pmuCount = int.Parse(m_iniFile[section, "NumberPMUs", "0"]); for (x = 0; x < pmuCount; x++) { // Create a new PMU cell for each PDC entry that exists pmuCell = new ConfigurationCell(this); // For BPA INI files, PMUs tradionally have an ID number indexed starting at zero or one - so we multiply // ID by 1000 and add index to attempt to create a fairly unique ID to help optimize downstream parsing pmuCell.IDCode = unchecked ((ushort)(pdcID * 1000 + x)); pmuCell.SectionEntry = string.Format("{0}pmu{1}", section, x); // This will automatically assign ID label as first 4 digits of section pmuCell.StationName = string.Format("{0} - Device {1}", m_iniFile[section, "Name", section], (x + 1)); pmuCell.PhasorDefinitions.Clear(); for (y = 0; y < 2; y++) { pmuCell.PhasorDefinitions.Add(new PhasorDefinition(pmuCell, y + 1, m_iniFile[section, "Phasor" + ((x * 2) + (y + 1)), DefaultVoltagePhasorEntry])); } pmuCell.FrequencyDefinition = new FrequencyDefinition(pmuCell, m_iniFile[section, "Frequency", DefaultFrequencyEntry]); m_configurationFileCells.Add(pmuCell); } } } } } // Associate single Macrodyne cell with its associated cell hopefully defined in INI file if (m_configurationFileCells.Count > 0 && (object)Cells != null && Cells.Count > 0) { ConfigurationCell configurationFileCell = null; // Assign INI file cell associating by section entry ConfigurationCell cell = Cells[0]; // Attempt to associate this configuration cell with information read from external INI based configuration file m_configurationFileCells.TryGetBySectionEntry(cell.SectionEntry, ref configurationFileCell); cell.ConfigurationFileCell = configurationFileCell; m_onlineDataFormatFlags = Common.GetFormatFlagsFromPhasorCount(cell.PhasorDefinitions.Count); m_stationName = cell.StationName; } } else { throw new InvalidOperationException("Macrodyne config file \"" + m_iniFile.FileName + "\" does not exist."); } } // In case other classes want to know, we send out a notification that the config file has been reloaded (make sure // you do this after the write lock has been released to avoid possible dead-lock situations) if (ConfigurationFileReloaded != null) { ConfigurationFileReloaded(this, EventArgs.Empty); } }