/// <summary> /// Creates a new <see cref="DataFrame"/> from specified parameters. /// </summary> /// <param name="timestamp">The exact timestamp, in <see cref="Ticks"/>, of the data represented by this <see cref="DataFrame"/>.</param> /// <param name="configurationFrame">The <see cref="ConfigurationFrame"/> associated with this <see cref="DataFrame"/>.</param> /// <remarks> /// This constructor is used by a consumer to generate an IEEE C37.118 data frame. /// </remarks> public DataFrame(Ticks timestamp, ConfigurationFrame1 configurationFrame) : base(new DataCellCollection(), timestamp, configurationFrame) { // Pass time-base along to DataFrame's common header if (!(configurationFrame is null)) { CommonHeader.Timebase = configurationFrame.Timebase; } }
/// <summary> /// Creates a new <see cref="CommonFrameHeader"/> from specified parameters. /// </summary> /// <param name="configurationFrame">IEEE C37.118 <see cref="ConfigurationFrame1"/> if available.</param> /// <param name="typeID">The IEEE C37.118 specific frame type of this frame.</param> /// <param name="idCode">The ID code of this frame.</param> /// <param name="timestamp">The timestamp of this frame.</param> /// <param name="version">The target version for this IEEE C37.118 frame.</param> public CommonFrameHeader(ConfigurationFrame1 configurationFrame, FrameType typeID, ushort idCode, Ticks timestamp, DraftRevision version) { m_frameType = typeID; m_idCode = idCode; m_timestamp = timestamp; m_version = (byte)version; m_timebase = (UInt24)100000; if (configurationFrame is null) { return; } // Hang on to configured frame rate and ticks per frame m_framesPerSecond = configurationFrame.FrameRate; m_ticksPerFrame = Ticks.PerSecond / (double)m_framesPerSecond; }
/// <summary> /// Creates a new <see cref="CommonFrameHeader"/> from given <paramref name="buffer"/>. /// </summary> /// <param name="configurationFrame">IEEE C37.118 <see cref="ConfigurationFrame1"/> 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(ConfigurationFrame1 configurationFrame, byte[] buffer, int startIndex) { const byte VersionNumberMask = (byte)IEEEC37_118.FrameType.VersionNumberMask; if (buffer[startIndex] != GemstonePhasorProtocolls.Common.SyncByte) { throw new InvalidOperationException($"Bad data stream, expected sync byte 0xAA as first byte in IEEE C37.118 frame, got 0x{buffer[startIndex].ToString("X").PadLeft(2, '0')}"); } // Strip out frame type and version information... m_frameType = (FrameType)(buffer[startIndex + 1] & ~VersionNumberMask); m_version = (byte)(buffer[startIndex + 1] & VersionNumberMask); m_frameLength = BigEndian.ToUInt16(buffer, startIndex + 2); m_idCode = BigEndian.ToUInt16(buffer, startIndex + 4); uint secondOfCentury = BigEndian.ToUInt32(buffer, startIndex + 6); uint fractionOfSecond = BigEndian.ToUInt32(buffer, startIndex + 10); // Without timebase, the best timestamp you can get is down to the whole second m_timestamp = new UnixTimeTag((decimal)secondOfCentury).ToDateTime().Ticks; if (!(configurationFrame is null)) { // If config frame is available, frames have enough information for sub-second time resolution m_timebase = configurationFrame.Timebase; // "Actual fractional seconds" are obtained by taking fractionOfSecond and dividing by timebase. // Since we are converting to ticks, we need to multiply by Ticks.PerSecond. // We do the multiplication first so that the whole operation can be done using integer arithmetic. // m_timebase / 2L is added before dividing by timebase in order to round the result. long ticksBeyondSecond = (fractionOfSecond & ~Common.TimeQualityFlagsMask) * Ticks.PerSecond; m_timestamp += (ticksBeyondSecond + m_timebase / 2L) / m_timebase; // Hang on to configured frame rate and ticks per frame m_framesPerSecond = configurationFrame.FrameRate; m_ticksPerFrame = Ticks.PerSecond / (double)m_framesPerSecond; } m_timeQualityFlags = fractionOfSecond & Common.TimeQualityFlagsMask; }
/// <summary> /// Creates a new <see cref="ConfigurationCell3"/> from specified parameters. /// </summary> /// <param name="parent">The reference to parent <see cref="ConfigurationFrame1"/> of this <see cref="ConfigurationCell3"/>.</param> /// <param name="idCode">The numeric ID code for this <see cref="ConfigurationCell3"/>.</param> /// <param name="nominalFrequency">The nominal Frequency of the <see cref="FrequencyDefinition"/> of this <see cref="ConfigurationCell3"/>.</param> public ConfigurationCell3(ConfigurationFrame1 parent, ushort idCode, double nominalFrequency) //FIXME: Does this need to use config frame 3? : this(parent) { IDCode = idCode; NominalFrequency = nominalFrequency; }
/// <summary> /// Creates a new <see cref="ConfigurationCell"/> from specified parameters. /// </summary> /// <param name="parent">The reference to parent <see cref="ConfigurationFrame1"/> of this <see cref="ConfigurationCell"/>.</param> /// <param name="idCode">The numeric ID code for this <see cref="ConfigurationCell"/>.</param> /// <param name="nominalFrequency">The nominal Frequency of the <see cref="FrequencyDefinition"/> of this <see cref="ConfigurationCell"/>.</param> public ConfigurationCell(ConfigurationFrame1 parent, ushort idCode, double nominalFrequency) : this(parent) { IDCode = idCode; NominalFrequency = nominalFrequency; }