Пример #1
0
        /// <summary>
        /// Parses the binary body 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 ParseBodyImage(byte[] buffer, int startIndex, int length)
        {
            ConfigurationCell  configCell      = ConfigurationCell;
            ConfigurationFrame configFrame     = configCell.Parent;
            ProtocolVersion    protocolVersion = configFrame.CommonHeader.ProtocolVersion;
            IPhasorValue       phasorValue;
            IDigitalValue      digitalValue;
            int parsedLength, index = startIndex;

            if (protocolVersion == ProtocolVersion.M)
            {
                // Parse out optional STATUS2 flags
                if (configFrame.Status2Included)
                {
                    m_status2Flags = buffer[index];
                    index++;
                }
                else
                {
                    m_status2Flags = 0;
                }

                // We interpret status bytes together as one word (matches other protocols this way)
                base.StatusFlags = Word.MakeWord((byte)Status1Flags, m_status2Flags);
            }
            else
            {
                // Read sample number for G protocol
                m_sampleNumber = BigEndian.ToUInt16(buffer, index);
                index         += 2;
            }

            // Parse out time tag
            if (configFrame.TimestampIncluded)
            {
                m_clockStatusFlags = (ClockStatusFlags)buffer[index];
                index += 1;

                ushort day      = BinaryCodedDecimal.Decode(BigEndian.ToUInt16(buffer, index));
                byte   hours    = BinaryCodedDecimal.Decode(buffer[index + 2]);
                byte   minutes  = BinaryCodedDecimal.Decode(buffer[index + 3]);
                byte   seconds  = BinaryCodedDecimal.Decode(buffer[index + 4]);
                double timebase = 2880.0D;
                index += 5;

                // Read sample number for M protocol
                if (protocolVersion == ProtocolVersion.M)
                {
                    m_sampleNumber = BigEndian.ToUInt16(buffer, index + 5);
                    timebase       = 719.0D;
                    index         += 2;
                }

                // TODO: Think about how to handle year change with floating clock...
                // Calculate timestamp
                Parent.Timestamp = new DateTime(DateTime.UtcNow.Year, 1, 1).AddDays(day - 1).AddHours(hours).AddMinutes(minutes).AddSeconds(seconds + m_sampleNumber / timebase);
            }
            else
            {
                Parent.Timestamp       = DateTime.UtcNow.Ticks;
                SynchronizationIsValid = false;
                m_sampleNumber         = BigEndian.ToUInt16(buffer, index);
                index += 2;
            }

            // Parse out first five phasor values (1 - 5)
            int phasorIndex = 0;

            // Phasor 1 (always present)
            phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
            PhasorValues.Add(phasorValue);
            index += parsedLength;

            if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor2Enabled) == OnlineDataFormatFlags.Phasor2Enabled)
            {
                // Phasor 2
                phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
                PhasorValues.Add(phasorValue);
                index += parsedLength;
            }

            if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor3Enabled) == OnlineDataFormatFlags.Phasor3Enabled)
            {
                // Phasor 3
                phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
                PhasorValues.Add(phasorValue);
                index += parsedLength;
            }

            if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor4Enabled) == OnlineDataFormatFlags.Phasor4Enabled)
            {
                // Phasor 4
                phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
                PhasorValues.Add(phasorValue);
                index += parsedLength;
            }

            if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor5Enabled) == OnlineDataFormatFlags.Phasor5Enabled)
            {
                // Phasor 5
                phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
                PhasorValues.Add(phasorValue);
                index += parsedLength;
            }

            // For 1690M format the frequency, reference phasor, dF/dt and first digital follow phasors 1-5
            if (protocolVersion == ProtocolVersion.M)
            {
                // Parse out frequency value
                FrequencyValue = Macrodyne.FrequencyValue.CreateNewValue(this, configCell.FrequencyDefinition, buffer, index, out parsedLength);
                index         += parsedLength;

                // Parse reference phasor information
                if (configFrame.ReferenceIncluded)
                {
                    m_referenceSampleNumber = BigEndian.ToUInt16(buffer, index);
                    m_referencePhasor       = PhasorValue.CreateNewValue(this, new PhasorDefinition(null, "Reference Phasor", PhasorType.Voltage, null), buffer, index, out parsedLength) as PhasorValue;
                    index += 6;
                }

                // Parse first digital value
                if (configFrame.Digital1Included)
                {
                    digitalValue = DigitalValue.CreateNewValue(this, configCell.DigitalDefinitions[0], buffer, index, out parsedLength);
                    DigitalValues.Add(digitalValue);
                    index += parsedLength;
                }
            }

            // Parse out next five phasor values (6 - 10)
            if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor6Enabled) == OnlineDataFormatFlags.Phasor6Enabled)
            {
                // Phasor 6
                phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
                PhasorValues.Add(phasorValue);
                index += parsedLength;
            }

            if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor7Enabled) == OnlineDataFormatFlags.Phasor7Enabled)
            {
                // Phasor 7
                phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
                PhasorValues.Add(phasorValue);
                index += parsedLength;
            }

            if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor8Enabled) == OnlineDataFormatFlags.Phasor8Enabled)
            {
                // Phasor 8
                phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
                PhasorValues.Add(phasorValue);
                index += parsedLength;
            }

            if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor9Enabled) == OnlineDataFormatFlags.Phasor9Enabled)
            {
                // Phasor 9
                phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
                PhasorValues.Add(phasorValue);
                index += parsedLength;
            }

            if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor10Enabled) == OnlineDataFormatFlags.Phasor10Enabled)
            {
                // Phasor 10
                phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
                PhasorValues.Add(phasorValue);
                index += parsedLength;
            }

            // For 1690G format the channel phasors, reference phasor, frequency, dF/dt and digitals follow phasors 1-10
            if (protocolVersion == ProtocolVersion.G)
            {
                // Technically 30 more possible channel phasors can be defined
                for (int i = phasorIndex; i < ConfigurationCell.PhasorDefinitions.Count; i++)
                {
                    phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
                    PhasorValues.Add(phasorValue);
                    index += parsedLength;
                }

                // Parse reference phasor information
                if (configFrame.ReferenceIncluded)
                {
                    m_referencePhasor = PhasorValue.CreateNewValue(this, new PhasorDefinition(null, "Reference Phasor", PhasorType.Voltage, null), buffer, index, out parsedLength) as PhasorValue;
                    index            += parsedLength;
                }

                // Parse out frequency value
                FrequencyValue = Macrodyne.FrequencyValue.CreateNewValue(this, configCell.FrequencyDefinition, buffer, index, out parsedLength);
                index         += parsedLength;

                // Parse first digital value
                if (configFrame.Digital1Included)
                {
                    digitalValue = DigitalValue.CreateNewValue(this, configCell.DigitalDefinitions[0], buffer, index, out parsedLength);
                    DigitalValues.Add(digitalValue);
                    index += parsedLength;
                }
            }

            // Parse second digital value
            if (configFrame.Digital2Included)
            {
                digitalValue = DigitalValue.CreateNewValue(this, configCell.DigitalDefinitions[configCell.DigitalDefinitions.Count - 1], buffer, index, out parsedLength);
                DigitalValues.Add(digitalValue);
                index += parsedLength;
            }

            // Return total parsed length
            return(index - startIndex);
        }
Пример #2
0
        /// <summary>
        /// Parses the <see cref="ControlFile"/>.
        /// </summary>
        /// <exception cref="InvalidOperationException">"No EMAX control file name was specified.</exception>
        /// <exception cref="FileNotFoundException">EMAX control file was not found.</exception>
        public void Parse()
        {
            if (string.IsNullOrEmpty(FileName))
            {
                throw new InvalidOperationException("No EMAX control file name was specified.");
            }

            if (!File.Exists(FileName))
            {
                throw new FileNotFoundException(string.Format("EMAX control file {0} not found.", FileName));
            }

            m_parsedSuccesses.Clear();
            m_parsedFailures.Clear();

            byte byteValue;

            using (FileStream stream = File.OpenRead(FileName))
            {
                // Read in header and file structure definitions
                using (BinaryReader reader = new BinaryReader(stream, Encoding.ASCII, true))
                {
                    // Read control header
                    Header = reader.ReadStructure <CTL_HEADER>();

                    // Read byte that defines number of analog channels
                    m_configuredAnalogChannels = BinaryCodedDecimal.Decode(Header.id.LowByte());

                    // Read byte that defines data size (i.e., 12 or 16 bits)
                    byteValue = Header.id.HighByte();

                    if (!Enum.IsDefined(typeof(DataSize), byteValue))
                    {
                        throw new InvalidOperationException("Invalid EMAX data size code encountered: 0x" + byteValue.ToString("X").PadLeft(2, '0'));
                    }

                    DataSize = (DataSize)byteValue;

                    // Create array of file structures
                    List <CTL_FILE_STRUCT> fileStructures = new List <CTL_FILE_STRUCT>();
                    CTL_FILE_STRUCT        fileStructure  = new CTL_FILE_STRUCT(reader);

                    // ReSharper disable once LoopVariableIsNeverChangedInsideLoop
                    while (fileStructure.type != StructureType.EndOfStructures)
                    {
                        if (fileStructure.type != StructureType.Unknown)
                        {
                            fileStructures.Add(fileStructure);
                        }

                        fileStructure = new CTL_FILE_STRUCT(reader);
                    }

                    FileStructures = fileStructures.ToArray();
                }

                // Read in actual file structures
                for (int index = 0; index < FileStructures.Length; index++)
                {
                    CTL_FILE_STRUCT fileStructure = FileStructures[index];

                    if (fileStructure.type == StructureType.Unknown)
                    {
                        continue;
                    }

                    // Set current type
                    m_currentType = fileStructure.type;

                    // Locate structure in the file
                    stream.Position = fileStructure.offset;

                    // Parse the structure type
                    using (BinaryReader reader = new BinaryReader(stream, Encoding.ASCII, true))
                    {
                        switch (m_currentType)
                        {
                        case StructureType.SYSTEM_PARAMETERS:
                            AttemptParse(() => SystemParameters = reader.ReadStructure <SYSTEM_PARAMETERS>());
                            break;

                        case StructureType.SYS_SETTINGS:
                            AttemptParse(() => SystemSettings = reader.ReadStructure <SYS_SETTINGS>());
                            break;

                        case StructureType.A_E_RSLTS:
                            AttemptParse(() => AnalogEventResults = new A_E_RSLTS(reader, m_configuredAnalogChannels, SystemParameters.analog_groups));
                            break;

                        case StructureType.ANALOG_GROUP:
                            AttemptParse(() => AnalogGroup = new ANALOG_GROUP(reader, m_configuredAnalogChannels));
                            break;

                        case StructureType.EVENT_GROUP:
                            AttemptParse(() => EventGroup = reader.ReadStructure <EVENT_GROUP>());
                            break;

                        case StructureType.ANLG_CHNL_NEW:
                            AttemptParse(() =>
                            {
                                AnalogChannelSettings = new Dictionary <int, ANLG_CHNL_NEW>();
                                ScalingFactors        = new Dictionary <int, double>();
                                ANLG_CHNL_NEW settings;

                                uint nextOffset = (index + 1 < FileStructures.Length) ? FileStructures[index + 1].offset : (uint)stream.Length;
                                uint length     = nextOffset - fileStructure.offset;
                                Func <ANLG_CHNL_NEW> channelFactory;

                                if (Marshal.SizeOf <ANLG_CHNL_NEW2>() * ConfiguredAnalogChannels <= length)
                                {
                                    channelFactory = () => reader.ReadStructure <ANLG_CHNL_NEW2>().ToAnlgChnlNew();
                                }
                                else
                                {
                                    channelFactory = () => reader.ReadStructure <ANLG_CHNL_NEW1>().ToAnlgChnlNew();
                                }

                                for (int i = 0; i < ConfiguredAnalogChannels; i++)
                                {
                                    settings = channelFactory();
                                    AnalogChannelSettings.Add(settings.ChannelNumber, settings);
                                    ScalingFactors.Add(settings.ChannelNumber, settings.ScalingFactor);
                                }
                            });
                            break;

                        case StructureType.EVNT_CHNL_NEW:
                            AttemptParse(() =>
                            {
                                EventChannelSettings = new Dictionary <int, EVNT_CHNL_NEW>();
                                EVNT_CHNL_NEW settings;

                                uint nextOffset = (index + 1 < FileStructures.Length) ? FileStructures[index + 1].offset : (uint)stream.Length;
                                uint length     = nextOffset - fileStructure.offset;
                                Func <EVNT_CHNL_NEW> channelFactory;

                                if (Marshal.SizeOf <EVNT_CHNL_NEW2>() * ConfiguredDigitalChannels <= length)
                                {
                                    channelFactory = () => reader.ReadStructure <EVNT_CHNL_NEW2>().ToEvntChnlNew();
                                }
                                else
                                {
                                    channelFactory = () => reader.ReadStructure <EVNT_CHNL_NEW1>().ToEvntChnlNew();
                                }

                                for (int i = 0; i < ConfiguredDigitalChannels; i++)
                                {
                                    settings = channelFactory();
                                    EventChannelSettings.Add(settings.EventNumber, settings);
                                }
                            });
                            break;

                        case StructureType.ANLG_CHNLS:
                            // TODO: Add decoder once structure definition is known...
                            m_parsedFailures.Add(new Tuple <StructureType, Exception>(m_currentType, new NotImplementedException()));
                            break;

                        case StructureType.SHORT_HEADER:
                            // TODO: Add decoder once structure definition is known...
                            m_parsedFailures.Add(new Tuple <StructureType, Exception>(m_currentType, new NotImplementedException()));
                            break;

                        case StructureType.FAULT_HEADER:
                            // TODO: Add decoder once structure definition is known...
                            m_parsedFailures.Add(new Tuple <StructureType, Exception>(m_currentType, new NotImplementedException()));
                            break;

                        case StructureType.EVENT_DISPLAY:
                            AttemptParse(() => EventDisplay = new EVENT_DISPLAY(reader, SystemParameters.event_groups));
                            break;

                        case StructureType.IDENTSTRING:
                            AttemptParse(() =>
                            {
                                IdentityString = reader.ReadStructure <IDENTSTRING>();
                                IdentityString.value.TruncateRight(IdentityString.length);
                            });
                            break;

                        case StructureType.A_SELECTION:
                            AttemptParse(() => AnalogSelection = new A_SELECTION(reader));
                            break;

                        case StructureType.E_GROUP_SELECT:
                            AttemptParse(() => EventGroupSelection = new E_GRP_SELECT(reader));
                            break;

                        case StructureType.PHASOR_GROUP:
                            AttemptParse(() => PhasorGroups = new PHASOR_GROUPS(reader));
                            break;

                        case StructureType.LINE_CONSTANTS:
                            AttemptParse(() => LineConstants = new LINE_CONSTANTS(reader));
                            break;

                        case StructureType.LINE_NAMES:
                            AttemptParse(() => LineNames = new LINE_NAMES(reader));
                            break;

                        case StructureType.FAULT_LOCATION:
                            AttemptParse(() => FaultLocations = new FAULT_LOCATIONS(reader));
                            break;

                        case StructureType.SENS_RSLTS:
                            AttemptParse(() => SensorResults = reader.ReadStructure <SENS_RSLTS>());
                            break;

                        case StructureType.SEQUENCE_CHANNELS:
                            AttemptParse(() => SequenceChannels = new SEQUENCE_CHANNELS(reader));
                            break;

                        case StructureType.TPwrRcd:
                            AttemptParse(() => PowerRecord = reader.ReadStructure <TPwrRcd>());
                            break;

                        case StructureType.BoardAnalogEventChannels:
                            AttemptParse(() => BoardAnalogEventChannels = reader.ReadStructure <BoardAnalogEventChannels>());
                            break;

                        case StructureType.BREAKER_TRIP_TIMES:
                            AttemptParse(() => BreakerTripTimes = new BREAKER_TRIP_TIMES(reader, m_configuredAnalogChannels, SystemParameters.analog_groups));
                            break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }
                }
            }
        }