Exemple #1
0
        /// <summary>
        /// Creates a new <see cref="CommonFrameHeader"/> from given <paramref name="buffer"/>.
        /// </summary>
        /// <param name="buffer">Buffer that contains data to parse.</param>
        /// <param name="startIndex">Start index into buffer where valid data begins.</param>
        public CommonFrameHeader(byte[] buffer, int startIndex)
        {
            // Validate SEL Fast Message data image
            if (buffer[startIndex] != Common.HeaderByte1 || buffer[startIndex + 1] != Common.HeaderByte2)
            {
                throw new InvalidOperationException($"Bad data stream, expected header bytes 0xA546 as first bytes in SEL Fast Message frame, got 0x{buffer[startIndex].ToString("X").PadLeft(2, '0')}{buffer[startIndex + 1].ToString("X").PadLeft(2, '0')}");
            }

            ushort     sampleCount;
            uint       secondOfCentury;
            NtpTimeTag timetag;

            // Parse relevant common header values
            m_frameSize     = (FrameSize)buffer[startIndex + 2];
            m_idCode        = BigEndian.ToUInt32(buffer, startIndex + 12);
            sampleCount     = BigEndian.ToUInt16(buffer, startIndex + 18);
            secondOfCentury = BigEndian.ToUInt32(buffer, startIndex + 20);

            // We use an NTP time tag since SEL Fast Message SOC also starts at 1/1/1900
            timetag = new NtpTimeTag(secondOfCentury, 0);

            // Data frames have subsecond time information, so we add this fraction of time to current seconds value
            timetag = new NtpTimeTag(timetag.Value + sampleCount * 50.0M / 1000.0M);

            // Cache timestamp value
            m_timestamp = timetag.ToDateTime().Ticks;
        }
Exemple #2
0
        /// <summary>
        /// Creates a new <see cref="CommonFrameHeader"/> from given <paramref name="buffer"/>.
        /// </summary>
        /// <param name="buffer">Buffer that contains data to parse.</param>
        /// <param name="startIndex">Start index into buffer where valid data begins.</param>
        public CommonFrameHeader(byte[] buffer, int startIndex)
        {
            uint secondOfCentury = BigEndian.ToUInt32(buffer, startIndex);

            m_sampleCount = BigEndian.ToUInt16(buffer, startIndex + 4);

            // We go ahead and pre-grab cell's status flags so we can determine framelength - we
            // leave startindex at 6 so that cell will be able to parse flags as needed - note
            // this increases needed common frame header size by 2 (i.e., BinaryLength + 2)
            m_statusFlags = BigEndian.ToUInt16(buffer, startIndex + FixedLength);

            // NTP timestamps based on NtpTimeTag class are designed to work for dates between
            // 1968-01-20 and 2104-02-26 based on recommended bit interpretation in RFC-2030.
            NtpTimeTag timetag = new NtpTimeTag(secondOfCentury, 0);

            // Cache timestamp value
            m_timestamp = timetag.ToDateTime().Ticks;
        }
Exemple #3
0
        /// <summary>
        /// Creates a new <see cref="CommonFrameHeader"/> from given <paramref name="buffer"/>.
        /// </summary>
        /// <param name="configurationFrame">IEEE 1344 <see cref="ConfigurationFrame"/> if already parsed.</param>
        /// <param name="buffer">Buffer that contains data to parse.</param>
        /// <param name="startIndex">Start index into buffer where valid data begins.</param>
        public CommonFrameHeader(ConfigurationFrame configurationFrame, byte[] buffer, int startIndex)
        {
            uint secondOfCentury = BigEndian.ToUInt32(buffer, startIndex);

            m_sampleCount = BigEndian.ToUInt16(buffer, startIndex + 4);

            // We go ahead and pre-grab cell's status flags so we can determine framelength - we
            // leave startindex at 6 so that cell will be able to parse flags as needed - note
            // this increases needed common frame header size by 2 (i.e., BinaryLength + 2)
            m_statusFlags = BigEndian.ToUInt16(buffer, startIndex + FixedLength);

            // NTP timestamps based on NtpTimeTag class are designed to work for dates between
            // 1968-01-20 and 2104-02-26 based on recommended bit interpretation in RFC-2030.
            NtpTimeTag timetag = new NtpTimeTag(secondOfCentury, 0);

            // Data frames have subsecond time information, so we add this fraction of time to current seconds value
            if (TypeID == IEEE1344.FrameType.DataFrame && configurationFrame != null)
            {
                timetag.Value += SampleCount / Math.Truncate((double)Common.MaximumSampleCount / (double)configurationFrame.Period) / (double)configurationFrame.FrameRate;
            }

            // Cache timestamp value
            m_timestamp = timetag.ToDateTime().Ticks;
        }
Exemple #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;
                }
            }
        }