/// <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; }
/// <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; }
/// <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; }