//******************************************************************************************************// EVEFile.cs - Gbtc//// Copyright © 2013, Grid Protection Alliance. All Rights Reserved.//// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See// the NOTICE file distributed with this work for additional information regarding copyright ownership.// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may// not use this file except in compliance with the License. You may obtain a copy of the License at://// http://www.opensource.org/licenses/MIT//// Unless agreed to in writing, the subject software distributed under the License is distributed on an// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the// License for the specific language governing permissions and limitations.//// Code Modification History:// ----------------------------------------------------------------------------------------------------// 11/05/2013 - Stephen C. Wills// Generated original version of source code.////****************************************************************************************************** using System;using System.Collections.Generic;using System.Globalization;using System.IO;using System.Linq;using System.Text;using System.Text.RegularExpressions;using GSF.Collections; namespace GSF.SELEventParser{ public class EventFile { #region [ Members ] // Nested Types private class Token { public string Text; public int StartIndex; public int EndIndex; public double Distance(Token t) { return Math.Abs(StartIndex - t.StartIndex) + Math.Abs(EndIndex - t.EndIndex); } public Token JoinWith(Token t) { Text = Text + " " + t.Text; EndIndex = StartIndex + Text.Length - 1; return this; } } // Fields private List<object> m_sections; #endregion #region [ Constructors ] public EventFile() { m_sections = new List<object>(); } #endregion #region [ Properties ] public List<EventReport> EventReports { get { return m_sections.OfType<EventReport>().ToList(); } } public List<EventHistory> EventHistories { get { return m_sections.OfType<EventHistory>().ToList(); } } #endregion #region [ Methods ] public void Add(EventReport eventReport) { m_sections.Add(eventReport); } public bool Remove(EventReport eventReport) { return m_sections.Remove(eventReport); } public void Add(EventHistory eventHistory) { m_sections.Add(eventHistory); } public bool Remove(EventHistory eventHistory) { return m_sections.Remove(eventHistory); } #endregion #region [ Static ] // Static Methods public static EventFile Parse(string filename) { string[] lineSeparators = { "\r\n", "\n\r", "\r", "\n" }; EventFile parsedFile = new EventFile(); string fileText = File.ReadAllText(filename); int firstLineSeparatorIndex = lineSeparators.Select(separator => fileText.IndexOf(separator)).Where(index => index >= 0).Min(); string lineSeparator = lineSeparators.First(separator => fileText.IndexOf(separator) == firstLineSeparatorIndex); string[] lines = fileText .Split(new string[] { lineSeparator }, StringSplitOptions.None) .Select(line => line.RemoveControlCharacters()) .ToArray(); int lineIndex = 0; string command; EventReport parsedEventReport; EventHistory parsedEventHistory; while (lineIndex < lines.Length) { // Parse next command from the file command = ParseCommand(lines, ref lineIndex); // Skip to the next nonblank line SkipBlanks(lines, ref lineIndex); if (command.ToUpper().Contains("EVE")) { parsedEventReport = ParseEventReport(lines, ref lineIndex); parsedEventReport.Command = command; parsedFile.Add(parsedEventReport); } else if (command.ToUpper().Contains("HIS")) { parsedEventHistory = ParseEventHistory(lines, ref lineIndex); parsedEventHistory.Command = command; parsedFile.Add(parsedEventHistory); } // Skip to the next nonblank line SkipBlanks(lines, ref lineIndex); } return parsedFile; } private static string ParseCommand(string[] lines, ref int index) { StringBuilder command = new StringBuilder(); string currentLine; int commandIndex; // Scan forward to the start of the next command if (index > 0) { while (index < lines.Length) { currentLine = lines[index]; if (currentLine.StartsWith("=>") || currentLine.StartsWith("=>>")) break; index++; } } commandIndex = index; // Parse consecutive command lines as one single command while (commandIndex < lines.Length) { currentLine = lines[commandIndex++]; // Skip over blank lines if (string.IsNullOrWhiteSpace(currentLine)) continue; // If this line isn't the first line in the file and it doesn't // start with => or =>>, it is not part of the command if (commandIndex > 1 && !currentLine.StartsWith("=>") && !currentLine.StartsWith("=>>")) break; // Append the command portion of the line to the command command.Append(currentLine.TrimStart('=', '>')); // Advance index to the line after this one index = commandIndex; } return command.ToString(); } private static EventReport ParseEventReport(string[] lines, ref int index) { EventReport eventReport = new EventReport(); int firmwareIndex; // Parse the report header eventReport.Header = ParseHeader(lines, ref index); // Skip to the next nonblank line SkipBlanks(lines, ref index); // Get the index of the line where // the firmware information is located firmwareIndex = index; // Parse the firmware and event number eventReport.Firmware = ParseFirmware(lines, ref firmwareIndex); eventReport.EventNumber = ParseEventNumber(lines, ref index); index = Math.Max(firmwareIndex, index); // Skip to the next nonblank line SkipBlanks(lines, ref index); // Parse the analog section of the report eventReport.AnalogSection = ParseAnalogSection(eventReport.Header.EventTime, lines, ref index); return eventReport; } private static EventHistory ParseEventHistory(string[] lines, ref int index) { EventHistory eventHistory = new EventHistory(); // Parse the report header eventHistory.Header = ParseHeader(lines, ref index); // Skip to the next nonblank line SkipBlanks(lines, ref index); // Parse event histories eventHistory.Histories = ParseEventHistoryRecords(lines, ref index); return eventHistory; } private static Header ParseHeader(string[] lines, ref int index) { const string HeaderLine1 = @"(\S.*)\s+Date:\s+(\S+)\s+Time:\s+(\S+)"; const string HeaderLine2 = @"(\S.*)(?:\s+Serial Number: (\d+))?"; Header header = new Header(); Match regexMatch; DateTime eventTime; string eventTimeString; int serialNumber; if (index < lines.Length) { // Apply regex match to get information contained on first line of header regexMatch = Regex.Match(lines[index], HeaderLine1); if (regexMatch.Success) { // Get relay ID from line 1 header.RelayID = regexMatch.Groups[1].Value.Trim(); // Build date/time string for parsing eventTimeString = string.Format("{0} {1}", regexMatch.Groups[2].Value, regexMatch.Groups[3].Value); // Get event time from line 1 if (TryParseDateTime(eventTimeString, out eventTime)) header.EventTime = eventTime; // Advance to the next line index++; if (index < lines.Length) { // Apply regex match to get information contained on second line of header regexMatch = Regex.Match(lines[index], HeaderLine2); if (regexMatch.Success) { // Get station ID and serial number from line 2 header.StationID = regexMatch.Groups[1].Value.Trim(); if (int.TryParse(regexMatch.Groups[2].Value, out serialNumber)) header.SerialNumber = serialNumber; // Advance to the next line index++; } } } } return header; } private static Firmware ParseFirmware(string[] lines, ref int index) { const string FirmwareIDRegex = @"FID=(\S+)"; const string ChecksumRegex = @"CID=(?:0x)?(\S+)"; Firmware firmware = new Firmware(); Match firmwareIDMatch; Match checksumMatch; // Firmware ID and checksum are on the same line -- // match both regular expressions with the first line firmwareIDMatch = Regex.Match(lines[index], FirmwareIDRegex); checksumMatch = Regex.Match(lines[index], ChecksumRegex); // Get the firmware ID if (firmwareIDMatch.Success) firmware.ID = firmwareIDMatch.Groups[1].Value; // Get the firmware checksum if (checksumMatch.Success) firmware.Checksum = Convert.ToInt32(checksumMatch.Groups[1].Value, 16); // If either match was a success, advance to the next line if (firmwareIDMatch.Success || checksumMatch.Success) index++; return firmware; } private static int ParseEventNumber(string[] lines, ref int index) { const string EventNumberRegex = @"Event Number = (\d+)"; // Match the regular expression to get the event number Match eventNumberMatch = Regex.Match(lines[index], EventNumberRegex); if (eventNumberMatch.Success) { // Match was successful so // advance to the next line index++; // Get the event number return Convert.ToInt32(eventNumberMatch.Groups[1].Value); } // Unable to get event number // so default to zero return 0; } private static AnalogSection ParseAnalogSection(DateTime eventTime, string[] lines, ref int index) { const string CycleHeader = @"^\[\d+\]$"; AnalogSection analogSection = new AnalogSection(); int headerLineIndex; int firstDataLineIndex; int dataLineIndex; int triggerLineIndex; string[] headers = null; string[] fields = null; int analogEndIndex = -1; double[] analogs; double analog = 0.0; Cycle<DateTime> currentTimeCycle = null; List<Cycle<double>> currentCycles = null; string currentLine; int sampleCount = 0; int eventSample = -1; int firstCycleCount; long timePerSample; // Scan forward to the first line of data firstDataLineIndex = index; while (firstDataLineIndex < lines.Length) { fields = Regex.Split(lines[firstDataLineIndex], @"\s|>|\*").Where(s => s != string.Empty).ToArray(); if (fields.Length > 0 && double.TryParse(fields[0], out analog)) break; firstDataLineIndex++; } if (firstDataLineIndex >= lines.Length) return analogSection; // Scan backward to find the header line headerLineIndex = firstDataLineIndex - 1; while (headerLineIndex >= index) { headers = lines[headerLineIndex].Split((char[])null, StringSplitOptions.RemoveEmptyEntries); if (headers.Length == fields.Length) break; headerLineIndex--; } if (headerLineIndex < index) return analogSection; // Scan forward to either the trigger or the // largest current, whichever comes first, // and use it to determine the analogEndIndex triggerLineIndex = firstDataLineIndex; while (firstDataLineIndex < lines.Length) { currentLine = lines[triggerLineIndex++]; // If the current line is empty or it matches the cycle header, skip it if (string.IsNullOrWhiteSpace(currentLine) || Regex.IsMatch(currentLine, CycleHeader)) continue; // If the length of the current line is not within one character // of the length of the first data line, assume we have reached // the end of the section and stop scanning lines if (Math.Abs(currentLine.Length - lines[firstDataLineIndex].Length) > 1) break; // Check if this is the trigger row analogEndIndex = currentLine.IndexOf('>'); if (analogEndIndex >= 0) break; // Check if this is the largest current row analogEndIndex = currentLine.IndexOf('*'); if (analogEndIndex >= 0) break; } // If analogEndIndex is valid, parse the header row again if (analogEndIndex >= 0 && analogEndIndex < lines[headerLineIndex].Length) headers = lines[headerLineIndex].Remove(analogEndIndex).Split((char[])null, StringSplitOptions.RemoveEmptyEntries); // Generate analog channels from header row analogSection.AnalogChannels = headers .Select(header => new Channel<double>() { Name = header }) .ToList(); // Scan through the lines of data dataLineIndex = firstDataLineIndex; while (dataLineIndex < lines.Length) { currentLine = lines[dataLineIndex++]; // Empty lines or cycle headers indicate start of next cycle if (string.IsNullOrWhiteSpace(currentLine) || Regex.IsMatch(currentLine, CycleHeader)) { // Two empty lines in a row indicates the end of the section if ((object)currentCycles == null) break; currentCycles = null; continue; } // If the line does not indicate the start of a cycle, // check the length to make sure we are still in the analog section if (Math.Abs(currentLine.Length - lines[firstDataLineIndex].Length) > 1) break; // Parse this line as a line of data if (analogEndIndex >= 0 && analogEndIndex < currentLine.Length) currentLine = currentLine.Remove(analogEndIndex); analogs = currentLine .Split((char[])null, StringSplitOptions.RemoveEmptyEntries) .TakeWhile(field => double.TryParse(field, out analog)) .Select(field => analog) .ToArray();Lines 1–500 of 756. Load more
//****************************************************************************************************** // EVEFile.cs - Gbtc // // Copyright © 2013, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 11/05/2013 - Stephen C. Wills // Generated original version of source code. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using GSF.Collections; namespace GSF.SELEventParser { public class EventFile { #region [ Members ] // Nested Types private class Token { public string Text; public int StartIndex; public int EndIndex; public double Distance(Token t) { return Math.Abs(StartIndex - t.StartIndex) + Math.Abs(EndIndex - t.EndIndex); } public Token JoinWith(Token t) { Text = Text + " " + t.Text; EndIndex = StartIndex + Text.Length - 1; return this; } } // Fields private List<object> m_sections; #endregion #region [ Constructors ] public EventFile() { m_sections = new List<object>(); } #endregion #region [ Properties ] public List<EventReport> EventReports { get { return m_sections.OfType<EventReport>().ToList(); } } public List<EventHistory> EventHistories { get { return m_sections.OfType<EventHistory>().ToList(); } } #endregion #region [ Methods ] public void Add(EventReport eventReport) { m_sections.Add(eventReport); } public bool Remove(EventReport eventReport) { return m_sections.Remove(eventReport); } public void Add(EventHistory eventHistory) { m_sections.Add(eventHistory); } public bool Remove(EventHistory eventHistory) { return m_sections.Remove(eventHistory); } #endregion #region [ Static ] // Static Methods public static EventFile Parse(string filename) { string[] lineSeparators = { "\r\n", "\n\r", "\r", "\n" }; EventFile parsedFile = new EventFile(); string fileText = File.ReadAllText(filename); int firstLineSeparatorIndex = lineSeparators.Select(separator => fileText.IndexOf(separator)).Where(index => index >= 0).Min(); string lineSeparator = lineSeparators.First(separator => fileText.IndexOf(separator) == firstLineSeparatorIndex); string[] lines = fileText .Split(new string[] { lineSeparator }, StringSplitOptions.None) .Select(line => line.RemoveControlCharacters()) .ToArray(); int lineIndex = 0; string command; EventReport parsedEventReport; EventHistory parsedEventHistory; while (lineIndex < lines.Length) { // Parse next command from the file command = ParseCommand(lines, ref lineIndex); // Skip to the next nonblank line SkipBlanks(lines, ref lineIndex); if (command.ToUpper().Contains("EVE")) { parsedEventReport = ParseEventReport(lines, ref lineIndex); parsedEventReport.Command = command; parsedFile.Add(parsedEventReport); } else if (command.ToUpper().Contains("HIS")) { parsedEventHistory = ParseEventHistory(lines, ref lineIndex); parsedEventHistory.Command = command; parsedFile.Add(parsedEventHistory); } // Skip to the next nonblank line SkipBlanks(lines, ref lineIndex); } return parsedFile; } private static string ParseCommand(string[] lines, ref int index) { StringBuilder command = new StringBuilder(); string currentLine; int commandIndex; // Scan forward to the start of the next command if (index > 0) { while (index < lines.Length) { currentLine = lines[index]; if (currentLine.StartsWith("=>") || currentLine.StartsWith("=>>")) break; index++; } } commandIndex = index; // Parse consecutive command lines as one single command while (commandIndex < lines.Length) { currentLine = lines[commandIndex++]; // Skip over blank lines if (string.IsNullOrWhiteSpace(currentLine)) continue; // If this line isn't the first line in the file and it doesn't // start with => or =>>, it is not part of the command if (commandIndex > 1 && !currentLine.StartsWith("=>") && !currentLine.StartsWith("=>>")) break; // Append the command portion of the line to the command command.Append(currentLine.TrimStart('=', '>')); // Advance index to the line after this one index = commandIndex; } return command.ToString(); } private static EventReport ParseEventReport(string[] lines, ref int index) { EventReport eventReport = new EventReport(); int firmwareIndex; // Parse the report header eventReport.Header = ParseHeader(lines, ref index); // Skip to the next nonblank line SkipBlanks(lines, ref index); // Get the index of the line where // the firmware information is located firmwareIndex = index; // Parse the firmware and event number eventReport.Firmware = ParseFirmware(lines, ref firmwareIndex); eventReport.EventNumber = ParseEventNumber(lines, ref index); index = Math.Max(firmwareIndex, index); // Skip to the next nonblank line SkipBlanks(lines, ref index); // Parse the analog section of the report eventReport.AnalogSection = ParseAnalogSection(eventReport.Header.EventTime, lines, ref index); return eventReport; } private static EventHistory ParseEventHistory(string[] lines, ref int index) { EventHistory eventHistory = new EventHistory(); // Parse the report header eventHistory.Header = ParseHeader(lines, ref index); // Skip to the next nonblank line SkipBlanks(lines, ref index); // Parse event histories eventHistory.Histories = ParseEventHistoryRecords(lines, ref index); return eventHistory; } private static Header ParseHeader(string[] lines, ref int index) { const string HeaderLine1 = @"(\S.*)\s+Date:\s+(\S+)\s+Time:\s+(\S+)"; const string HeaderLine2 = @"(\S.*)(?:\s+Serial Number: (\d+))?"; Header header = new Header(); Match regexMatch; DateTime eventTime; string eventTimeString; int serialNumber; if (index < lines.Length) { // Apply regex match to get information contained on first line of header regexMatch = Regex.Match(lines[index], HeaderLine1); if (regexMatch.Success) { // Get relay ID from line 1 header.RelayID = regexMatch.Groups[1].Value.Trim(); // Build date/time string for parsing eventTimeString = string.Format("{0} {1}", regexMatch.Groups[2].Value, regexMatch.Groups[3].Value); // Get event time from line 1 if (TryParseDateTime(eventTimeString, out eventTime)) header.EventTime = eventTime; // Advance to the next line index++; if (index < lines.Length) { // Apply regex match to get information contained on second line of header regexMatch = Regex.Match(lines[index], HeaderLine2); if (regexMatch.Success) { // Get station ID and serial number from line 2 header.StationID = regexMatch.Groups[1].Value.Trim(); if (int.TryParse(regexMatch.Groups[2].Value, out serialNumber)) header.SerialNumber = serialNumber; // Advance to the next line index++; } } } } return header; } private static Firmware ParseFirmware(string[] lines, ref int index) { const string FirmwareIDRegex = @"FID=(\S+)"; const string ChecksumRegex = @"CID=(?:0x)?(\S+)"; Firmware firmware = new Firmware(); Match firmwareIDMatch; Match checksumMatch; // Firmware ID and checksum are on the same line -- // match both regular expressions with the first line firmwareIDMatch = Regex.Match(lines[index], FirmwareIDRegex); checksumMatch = Regex.Match(lines[index], ChecksumRegex); // Get the firmware ID if (firmwareIDMatch.Success) firmware.ID = firmwareIDMatch.Groups[1].Value; // Get the firmware checksum if (checksumMatch.Success) firmware.Checksum = Convert.ToInt32(checksumMatch.Groups[1].Value, 16); // If either match was a success, advance to the next line if (firmwareIDMatch.Success || checksumMatch.Success) index++; return firmware; } private static int ParseEventNumber(string[] lines, ref int index) { const string EventNumberRegex = @"Event Number = (\d+)"; // Match the regular expression to get the event number Match eventNumberMatch = Regex.Match(lines[index], EventNumberRegex); if (eventNumberMatch.Success) { // Match was successful so // advance to the next line index++; // Get the event number return Convert.ToInt32(eventNumberMatch.Groups[1].Value); } // Unable to get event number // so default to zero return 0; } private static AnalogSection ParseAnalogSection(DateTime eventTime, string[] lines, ref int index) { const string CycleHeader = @"^\[\d+\]$"; AnalogSection analogSection = new AnalogSection(); int headerLineIndex; int firstDataLineIndex; int dataLineIndex; int triggerLineIndex; string[] headers = null; string[] fields = null; int analogEndIndex = -1; double[] analogs; double analog = 0.0; Cycle<DateTime> currentTimeCycle = null; List<Cycle<double>> currentCycles = null; string currentLine; int sampleCount = 0; int eventSample = -1; int firstCycleCount; long timePerSample; // Scan forward to the first line of data firstDataLineIndex = index; while (firstDataLineIndex < lines.Length) { fields = Regex.Split(lines[firstDataLineIndex], @"\s|>|\*").Where(s => s != string.Empty).ToArray(); if (fields.Length > 0 && double.TryParse(fields[0], out analog)) break; firstDataLineIndex++; } if (firstDataLineIndex >= lines.Length) return analogSection; // Scan backward to find the header line headerLineIndex = firstDataLineIndex - 1; while (headerLineIndex >= index) { headers = lines[headerLineIndex].Split((char[])null, StringSplitOptions.RemoveEmptyEntries); if (headers.Length == fields.Length) break; headerLineIndex--; } if (headerLineIndex < index) return analogSection; // Scan forward to either the trigger or the // largest current, whichever comes first, // and use it to determine the analogEndIndex triggerLineIndex = firstDataLineIndex; while (firstDataLineIndex < lines.Length) { currentLine = lines[triggerLineIndex++]; // If the current line is empty or it matches the cycle header, skip it if (string.IsNullOrWhiteSpace(currentLine) || Regex.IsMatch(currentLine, CycleHeader)) continue; // If the length of the current line is not within one character // of the length of the first data line, assume we have reached // the end of the section and stop scanning lines if (Math.Abs(currentLine.Length - lines[firstDataLineIndex].Length) > 1) break; // Check if this is the trigger row analogEndIndex = currentLine.IndexOf('>'); if (analogEndIndex >= 0) break; // Check if this is the largest current row analogEndIndex = currentLine.IndexOf('*'); if (analogEndIndex >= 0) break; } // If analogEndIndex is valid, parse the header row again if (analogEndIndex >= 0 && analogEndIndex < lines[headerLineIndex].Length) headers = lines[headerLineIndex].Remove(analogEndIndex).Split((char[])null, StringSplitOptions.RemoveEmptyEntries); // Generate analog channels from header row analogSection.AnalogChannels = headers .Select(header => new Channel<double>() { Name = header }) .ToList(); // Scan through the lines of data dataLineIndex = firstDataLineIndex; while (dataLineIndex < lines.Length) { currentLine = lines[dataLineIndex++]; // Empty lines or cycle headers indicate start of next cycle if (string.IsNullOrWhiteSpace(currentLine) || Regex.IsMatch(currentLine, CycleHeader)) { // Two empty lines in a row indicates the end of the section if ((object)currentCycles == null) break; currentCycles = null; continue; } // If the line does not indicate the start of a cycle, // check the length to make sure we are still in the analog section if (Math.Abs(currentLine.Length - lines[firstDataLineIndex].Length) > 1) break; // Parse this line as a line of data if (analogEndIndex >= 0 && analogEndIndex < currentLine.Length) currentLine = currentLine.Remove(analogEndIndex); analogs = currentLine .Split((char[])null, StringSplitOptions.RemoveEmptyEntries) .TakeWhile(field => double.TryParse(field, out analog)) .Select(field => analog) .ToArray();