/// <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 not 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> public CommonFrameHeader(ConfigurationFrame1 configurationFrame, FrameType typeID, ushort idCode, Ticks timestamp) { m_frameType = typeID; m_idCode = idCode; m_timestamp = timestamp; m_version = 1; m_timebase = (UInt24)100000; if ((object)configurationFrame != null) { // 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 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] != PhasorProtocols.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((double)secondOfCentury)).ToDateTime().Ticks; if ((object)configurationFrame != null) { long ticksBeyondSecond; // 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. 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="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 <see cref="LineFrequency"/> of the <see cref="FrequencyDefinition"/> of this <see cref="ConfigurationCell"/>.</param> public ConfigurationCell(ConfigurationFrame1 parent, ushort idCode, LineFrequency nominalFrequency) : this(parent) { IDCode = idCode; NominalFrequency = nominalFrequency; }
/// <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 <see cref="LineFrequency"/> of the <see cref="FrequencyDefinition"/> of this <see cref="ConfigurationCell3"/>.</param> public ConfigurationCell3(ConfigurationFrame1 parent, ushort idCode, LineFrequency nominalFrequency) //FIXME: Does this need to use config frame 3? : this(parent) { IDCode = idCode; NominalFrequency = nominalFrequency; }
/// <summary> /// Casts the parsed <see cref="IChannelFrame"/> to its specific implementation (i.e., <see cref="DataFrame"/>, <see cref="ConfigurationFrame"/>, <see cref="CommandFrame"/> or <see cref="HeaderFrame"/>). /// </summary> /// <param name="frame"><see cref="IChannelFrame"/> that was parsed by <see cref="FrameImageParserBase{TTypeIdentifier,TOutputType}"/> that implements protocol specific common frame header interface.</param> protected override void OnReceivedChannelFrame(IChannelFrame frame) { // Raise abstract channel frame events as a priority (i.e., IDataFrame, IConfigurationFrame, etc.) base.OnReceivedChannelFrame(frame); // Raise IEEE C37.118 specific channel frame events, if any have been subscribed if (frame != null && (ReceivedDataFrame != null || ReceivedConfigurationFrame2 != null || ReceivedConfigurationFrame1 != null || ReceivedHeaderFrame != null || ReceivedCommandFrame != null)) { DataFrame dataFrame = frame as DataFrame; if (dataFrame != null) { if (ReceivedDataFrame != null) { ReceivedDataFrame(this, new EventArgs <DataFrame>(dataFrame)); } } else { // Configuration frame type 2 is more specific than type 1 (and more common), so we check it first ConfigurationFrame2 configFrame2 = frame as ConfigurationFrame2; if (configFrame2 != null) { if (ReceivedConfigurationFrame2 != null) { ReceivedConfigurationFrame2(this, new EventArgs <ConfigurationFrame2>(configFrame2)); } } else { ConfigurationFrame1 configFrame1 = frame as ConfigurationFrame1; if (configFrame1 != null) { if (ReceivedConfigurationFrame1 != null) { ReceivedConfigurationFrame1(this, new EventArgs <ConfigurationFrame1>(configFrame1)); } } else { HeaderFrame headerFrame = frame as HeaderFrame; if (headerFrame != null) { if (ReceivedHeaderFrame != null) { ReceivedHeaderFrame(this, new EventArgs <HeaderFrame>(headerFrame)); } } else { CommandFrame commandFrame = frame as CommandFrame; if (commandFrame != null) { if (ReceivedCommandFrame != null) { ReceivedCommandFrame(this, new EventArgs <CommandFrame>(commandFrame)); } } } } } } } }