示例#1
0
 /// <summary>
 /// Creates a new <see cref="DataFrame"/> 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 DataFrame(SerializationInfo info, StreamingContext context)
     : base(info, context)
 {
     // Deserialize data frame
     m_frameHeader  = (CommonFrameHeader)info.GetValue("frameHeader", typeof(CommonFrameHeader));
     m_sampleNumber = info.GetUInt16("sampleNumber");
 }
示例#2
0
        /// <summary>
        /// Parses a common header instance that implements <see cref="ICommonHeader{TTypeIdentifier}"/> for the output type represented
        /// in the binary image.
        /// </summary>
        /// <param name="buffer">Buffer containing data to parse.</param>
        /// <param name="offset">Offset index into buffer that represents where to start parsing.</param>
        /// <param name="length">Maximum length of valid data from offset.</param>
        /// <returns>The <see cref="ICommonHeader{TTypeIdentifier}"/> which includes a type ID for the <see cref="Type"/> to be parsed.</returns>
        /// <remarks>
        /// <para>
        /// Derived classes need to provide a common header instance (i.e., class that implements <see cref="ICommonHeader{TTypeIdentifier}"/>)
        /// for the output types; this will primarily include an ID of the <see cref="Type"/> that the data image represents.  This parsing is
        /// only for common header information, actual parsing will be handled by output type via its <see cref="ISupportBinaryImage.ParseBinaryImage"/>
        /// method. This header image should also be used to add needed complex state information about the output type being parsed if needed.
        /// </para>
        /// <para>
        /// If there is not enough buffer available to parse common header (as determined by <paramref name="length"/>), return null.  Also, if
        /// the protocol allows frame length to be determined at the time common header is being parsed and there is not enough buffer to parse
        /// the entire frame, it will be optimal to prevent further parsing by returning null.
        /// </para>
        /// </remarks>
        protected override ICommonHeader <FrameType> ParseCommonHeader(byte[] buffer, int offset, int length)
        {
            // See if there is enough data in the buffer to parse the common frame header.
            if (length >= CommonFrameHeader.FixedLength)
            {
                // Parse common frame header
                CommonFrameHeader parsedFrameHeader = new CommonFrameHeader(m_parseWordCountFromByte, m_usePhasorDataFileFormat, m_configurationFrame, buffer, offset, length);

                // As an optimization, we also make sure entire frame buffer image is available to be parsed - by doing this
                // we eliminate the need to validate length on all subsequent data elements that comprise the frame
                if (length >= parsedFrameHeader.FrameLength)
                {
                    // Expose the frame buffer image in case client needs this data for any reason
                    OnReceivedFrameBufferImage(parsedFrameHeader.FrameType, buffer, offset, parsedFrameHeader.FrameLength);

                    // Handle special parsing states
                    switch (parsedFrameHeader.TypeID)
                    {
                    case FrameType.DataFrame:
                        // Assign data frame parsing state
                        parsedFrameHeader.State = new DataFrameParsingState(parsedFrameHeader.FrameLength, m_configurationFrame, DataCell.CreateNewCell, TrustHeaderLength, ValidateDataFrameCheckSum);
                        break;

                    case FrameType.ConfigurationFrame:
                        // Assign configuration frame parsing state
                        parsedFrameHeader.State = new ConfigurationFrameParsingState(parsedFrameHeader.FrameLength, m_configurationFileName, ConfigurationCell.CreateNewCell, TrustHeaderLength, ValidateConfigurationFrameCheckSum);
                        break;
                    }

                    return(parsedFrameHeader);
                }
            }

            return(null);
        }
示例#3
0
        /// <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_packetsPerSample = info.GetUInt16("packetsPerSample");
            m_streamType       = (StreamType)info.GetValue("streamType", typeof(StreamType));
            m_revisionNumber   = (RevisionNumber)info.GetValue("revisionNumber", typeof(RevisionNumber));
            m_iniFile          = new IniFile(info.GetString("configurationFileName"));

            // The usePhasorDataFileFormat flag and other new elements did not exist in prior versions so we protect against possible deserialization failures
            try
            {
                UsePhasorDataFileFormat = info.GetBoolean("usePhasorDataFileFormat");
                m_rowLength             = info.GetUInt32("rowLength");
            }
            catch (SerializationException)
            {
                UsePhasorDataFileFormat = false;
                m_rowLength             = 0;
            }

            Refresh(false);
        }
示例#4
0
        /// <summary>
        /// Creates a new <see cref="CommonFrameHeader"/> from given <paramref name="buffer"/>.
        /// </summary>
        /// <param name="parseWordCountFromByte">Defines flag that interprets word count in packet header from a byte instead of a word.</param>
        /// <param name="usePhasorDataFileFormat">Defines flag that determines if source data is in the Phasor Data File Format (i.e., a DST file).</param>
        /// <param name="configFrame">Previously parsed configuration frame, if available.</param>
        /// <param name="buffer">Buffer that contains data to parse.</param>
        /// <param name="startIndex">Start index into buffer where valid data begins.</param>
        /// <param name="length">Maximum length of valid data from start index.</param>
        public CommonFrameHeader(bool parseWordCountFromByte, bool usePhasorDataFileFormat, ConfigurationFrame configFrame, byte[] buffer, int startIndex, int length)
        {
            uint secondOfCentury;

            // Determines if format is for DST file or streaming data
            m_usePhasorDataFileFormat = usePhasorDataFileFormat;

            if (m_usePhasorDataFileFormat)
            {
                // Handle phasor file format data protocol steps
                if (buffer[startIndex] == PhasorProtocols.Common.SyncByte && buffer[startIndex + 1] == Common.PhasorFileFormatFlag)
                {
                    // Bail out and leave frame length zero if there's not enough buffer to parse complete fixed portion of header
                    if (length >= DstHeaderFixedLength)
                    {
                        // Read full DST header
                        m_packetNumber = (byte)BPAPDCstream.FrameType.ConfigurationFrame;
                        m_fileType     = (FileType)buffer[startIndex + 2];
                        m_fileVersion  = (FileVersion)buffer[startIndex + 3];
                        m_sourceID     = Encoding.ASCII.GetString(buffer, startIndex + 4, 4);
                        uint headerLength = BigEndian.ToUInt32(buffer, startIndex + 8);
                        secondOfCentury = BigEndian.ToUInt32(buffer, startIndex + 12);

                        switch (m_fileType)
                        {
                        case FileType.PdcNtp:
                            RoughTimestamp = new NtpTimeTag(secondOfCentury, 0).ToDateTime().Ticks;
                            break;

                        case FileType.PdcUnix:
                            RoughTimestamp = new UnixTimeTag(secondOfCentury).ToDateTime().Ticks;
                            break;

                        default:
                            RoughTimestamp = 0;
                            break;
                        }

                        m_startSample    = BigEndian.ToUInt32(buffer, startIndex + 16);
                        m_sampleInterval = BigEndian.ToUInt16(buffer, startIndex + 20);
                        m_sampleRate     = BigEndian.ToUInt16(buffer, startIndex + 22);
                        m_rowLength      = BigEndian.ToUInt32(buffer, startIndex + 24);
                        m_totalRows      = BigEndian.ToUInt32(buffer, startIndex + 28);
                        secondOfCentury  = BigEndian.ToUInt32(buffer, startIndex + 32);

                        switch (m_fileType)
                        {
                        case FileType.PdcNtp:
                            m_triggerTime = new NtpTimeTag(secondOfCentury, 0).ToDateTime().Ticks;
                            break;

                        case FileType.PdcUnix:
                            m_triggerTime = new UnixTimeTag(secondOfCentury).ToDateTime().Ticks;
                            break;

                        default:
                            m_triggerTime = 0;
                            break;
                        }

                        m_triggerSample   = BigEndian.ToUInt32(buffer, startIndex + 36);
                        m_preTriggerRows  = BigEndian.ToUInt32(buffer, startIndex + 40);
                        m_triggerPMU      = BigEndian.ToUInt16(buffer, startIndex + 44);
                        m_triggerType     = BigEndian.ToUInt16(buffer, startIndex + 46);
                        m_userInformation = Encoding.ASCII.GetString(buffer, startIndex + 48, 80).Trim();
                        m_pmuCount        = BigEndian.ToUInt32(buffer, startIndex + 128);
                        FrameLength       = unchecked ((ushort)headerLength);
                    }
                }
                else
                {
                    // Must assume this is a data row if there are no sync bytes
                    m_packetNumber = (byte)BPAPDCstream.FrameType.DataFrame;
                    m_rowFlags     = BigEndian.ToUInt32(buffer, startIndex);

                    if (configFrame is null)
                    {
                        FrameLength = FixedLength;
                    }
                    else
                    {
                        uint sampleIndex = configFrame.SampleIndex;
                        CommonFrameHeader configFrameHeader = configFrame.CommonHeader;

                        if (configFrameHeader is null)
                        {
                            FrameLength = FixedLength;
                        }
                        else
                        {
                            // Assign row length to make sure parser knows how much data it needs
                            FrameLength = unchecked ((ushort)configFrameHeader.RowLength);

                            // Calculate timestamp as offset plus sample index * frame rate
                            RoughTimestamp = configFrameHeader.RoughTimestamp + Ticks.FromSeconds(sampleIndex * (1.0D / configFrameHeader.FrameRate));
                        }

                        // Increment sample index for next row
                        configFrame.SampleIndex = sampleIndex + 1;
                    }
                }
            }
            else
            {
                // Handle streaming data protocol steps
                if (buffer[startIndex] != PhasorProtocols.Common.SyncByte)
                {
                    throw new InvalidOperationException($"Bad data stream, expected sync byte 0xAA as first byte in BPA PDCstream frame, got 0x{buffer[startIndex].ToString("X").PadLeft(2, '0')}");
                }

                // Get packet number
                m_packetNumber = buffer[startIndex + 1];

                // Some older streams have a bad word count (e.g., some data streams have a 0x01 as the third byte
                // in the stream - this should be a 0x00 to make the word count come out correctly).  The following
                // compensates for this erratic behavior
                m_wordCount = parseWordCountFromByte ? buffer[startIndex + 3] : BigEndian.ToUInt16(buffer, startIndex + 2);

                // If this is a data frame get a rough timestamp down to the second (full parse will get accurate timestamp), this way
                // data frames that don't get fully parsed because configuration hasn't been received will still show a timestamp
                if (m_packetNumber > 0 && length > 8)
                {
                    secondOfCentury = BigEndian.ToUInt32(buffer, startIndex + 4);

                    // Until configuration is available, we make a guess at time tag type - this will just be
                    // used for display purposes until a configuration frame arrives.  If second of century
                    // is greater than 3155673600 (SOC value for NTP timestamp 1/1/2007), then this is likely
                    // an NTP time stamp (else this is a Unix time tag for the year 2069 - not likely).
                    RoughTimestamp = secondOfCentury > 3155673600 ?
                                     new NtpTimeTag(secondOfCentury, 0).ToDateTime().Ticks :
                                     new UnixTimeTag(secondOfCentury).ToDateTime().Ticks;
                }
            }
        }