Ejemplo n.º 1
0
        /// <summary>
        /// Creates a new IEEE C37.118 specific <see cref="DataFrame"/> for the given <paramref name="timestamp"/>.
        /// </summary>
        /// <param name="timestamp">Timestamp for new <see cref="IFrame"/> in <see cref="Ticks"/>.</param>
        /// <param name="configurationFrame">Associated <see cref="ConfigurationFrame1"/> for the new <see cref="DataFrame"/>.</param>
        /// <returns>New IEEE C37.118 <see cref="DataFrame"/> at given <paramref name="timestamp"/>.</returns>
        public static DataFrame CreateDataFrame(Ticks timestamp, ConfigurationFrame1 configurationFrame)
        {
            // We create a new IEEE C37.118 data frame based on current configuration frame
            DataFrame dataFrame = new DataFrame(timestamp, configurationFrame);

            foreach (ConfigurationCell configurationCell in configurationFrame.Cells)
            {
                // Create a new IEEE C37.118 data cell (i.e., a PMU entry for this frame)
                DataCell dataCell = new DataCell(dataFrame, configurationCell, true);

                // Add data cell to the frame
                dataFrame.Cells.Add(dataCell);
            }

            return(dataFrame);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Converts given IEEE C37.118 type 2 <paramref name="sourceFrame"/> into a type 1 configuration frame.
        /// </summary>
        /// <param name="sourceFrame">Source configuration frame.</param>
        /// <returns>New <see cref="ConfigurationFrame1"/> frame based on source configuration.</returns>
        /// <remarks>
        /// This function allow an explicit downcast of a typical IEEE C37.118 configuration type 2 frame to a type 1 frame.
        /// </remarks>
        public static ConfigurationFrame1 CastToConfigurationFrame1(ConfigurationFrame2 sourceFrame)
        {
            ConfigurationFrame1 derivedFrame;

            // Create a new IEEE C37.118 configuration frame converted from equivalent configuration information
            ConfigurationCell derivedCell;

            if (sourceFrame.DraftRevision == DraftRevision.Draft7)
            {
                derivedFrame = new ConfigurationFrame1(sourceFrame.Timebase, sourceFrame.IDCode, sourceFrame.Timestamp, sourceFrame.FrameRate);
            }
            else
            {
                derivedFrame = new ConfigurationFrame1Draft6(sourceFrame.Timebase, sourceFrame.IDCode, sourceFrame.Timestamp, sourceFrame.FrameRate);
            }

            foreach (ConfigurationCell sourceCell in sourceFrame.Cells)
            {
                // Create new derived configuration cell
                derivedCell = new ConfigurationCell(derivedFrame, sourceCell.IDCode, sourceCell.NominalFrequency);

                string stationName = sourceCell.StationName;
                string idLabel     = sourceCell.IDLabel;

                if (!string.IsNullOrWhiteSpace(stationName))
                {
                    derivedCell.StationName = stationName.TruncateLeft(derivedCell.MaximumStationNameLength);
                }

                if (!string.IsNullOrWhiteSpace(idLabel))
                {
                    derivedCell.IDLabel = idLabel.TruncateLeft(derivedCell.IDLabelLength);
                }

                derivedCell.PhasorCoordinateFormat = sourceCell.PhasorCoordinateFormat;
                derivedCell.PhasorAngleFormat      = sourceCell.PhasorAngleFormat;
                derivedCell.PhasorDataFormat       = sourceCell.PhasorDataFormat;
                derivedCell.FrequencyDataFormat    = sourceCell.FrequencyDataFormat;
                derivedCell.AnalogDataFormat       = sourceCell.AnalogDataFormat;

                // Create equivalent derived phasor definitions
                foreach (PhasorDefinition sourcePhasor in sourceCell.PhasorDefinitions)
                {
                    derivedCell.PhasorDefinitions.Add(new PhasorDefinition(derivedCell, sourcePhasor.Label, sourcePhasor.ScalingValue, sourcePhasor.Offset, sourcePhasor.PhasorType, null));
                }

                // Create equivalent derived frequency definition
                FrequencyDefinition sourceFrequency = sourceCell.FrequencyDefinition as FrequencyDefinition;
                derivedCell.FrequencyDefinition = new FrequencyDefinition(derivedCell, sourceFrequency?.Label);

                // Create equivalent derived analog definitions (assuming analog type = SinglePointOnWave)
                foreach (IAnalogDefinition sourceAnalog in sourceCell.AnalogDefinitions)
                {
                    derivedCell.AnalogDefinitions.Add(new AnalogDefinition(derivedCell, sourceAnalog.Label, sourceAnalog.ScalingValue, sourceAnalog.Offset, sourceAnalog.AnalogType));
                }

                // Create equivalent derived digital definitions
                foreach (IDigitalDefinition sourceDigital in sourceCell.DigitalDefinitions)
                {
                    derivedCell.DigitalDefinitions.Add(new GSF.PhasorProtocols.IEEEC37_118.DigitalDefinition(derivedCell, sourceDigital.Label, 0, 0));
                }

                // Add cell to frame
                derivedFrame.Cells.Add(derivedCell);
            }

            return(derivedFrame);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Handles incoming commands from devices connected over the command channel.
        /// </summary>
        /// <param name="clientID">Guid of client that sent the command.</param>
        /// <param name="connectionID">Remote client connection identification (i.e., IP:Port).</param>
        /// <param name="commandBuffer">Data buffer received from connected client device.</param>
        /// <param name="length">Valid length of data within the buffer.</param>
        protected override void DeviceCommandHandler(Guid clientID, string connectionID, byte[] commandBuffer, int length)
        {
            try
            {
                // Interpret data received from a client as a command frame
                CommandFrame commandFrame   = new CommandFrame(commandBuffer, 0, length);
                IServer      commandChannel = (IServer)CommandChannel ?? DataChannel;

                // Validate incoming ID code if requested
                if (!m_validateIDCode || commandFrame.IDCode == this.IDCode)
                {
                    switch (commandFrame.Command)
                    {
                    case DeviceCommand.SendConfigurationFrame1:
                        if (commandChannel != null)
                        {
                            ConfigurationFrame1 configFrame1 = CastToConfigurationFrame1(m_configurationFrame);
                            commandChannel.SendToAsync(clientID, configFrame1.BinaryImage, 0, configFrame1.BinaryLength);
                            OnStatusMessage(MessageLevel.Info, $"Received request for \"{commandFrame.Command}\" from \"{connectionID}\" - type 1 config frame was returned.");
                        }
                        break;

                    case DeviceCommand.SendConfigurationFrame2:
                        if (commandChannel != null)
                        {
                            commandChannel.SendToAsync(clientID, m_configurationFrame.BinaryImage, 0, m_configurationFrame.BinaryLength);
                            OnStatusMessage(MessageLevel.Info, $"Received request for \"{commandFrame.Command}\" from \"{connectionID}\" - type 2 config frame was returned.");
                        }
                        break;

                    case DeviceCommand.SendHeaderFrame:
                        if (commandChannel != null)
                        {
                            StringBuilder status = new StringBuilder();
                            status.Append("IEEE C37.118 Concentrator:\r\n\r\n");
                            status.AppendFormat(" Auto-publish config frame: {0}\r\n", AutoPublishConfigurationFrame);
                            status.AppendFormat("   Auto-start data channel: {0}\r\n", AutoStartDataChannel);
                            status.AppendFormat("       Data stream ID code: {0}\r\n", IDCode);
                            status.AppendFormat("       Derived system time: {0} UTC\r\n", ((DateTime)RealTime).ToString("yyyy-MM-dd HH:mm:ss.fff"));

                            HeaderFrame headerFrame = new HeaderFrame(status.ToString());
                            commandChannel.SendToAsync(clientID, headerFrame.BinaryImage, 0, headerFrame.BinaryLength);
                            OnStatusMessage(MessageLevel.Info, $"Received request for \"SendHeaderFrame\" from \"{connectionID}\" - frame was returned.");
                        }
                        break;

                    case DeviceCommand.EnableRealTimeData:
                        // Only responding to stream control command if auto-start data channel is false
                        if (!AutoStartDataChannel)
                        {
                            StartDataChannel();
                            OnStatusMessage(MessageLevel.Info, $"Received request for \"EnableRealTimeData\" from \"{connectionID}\" - concentrator real-time data stream was started.");
                        }
                        else
                        {
                            OnStatusMessage(MessageLevel.Info, $"Request for \"EnableRealTimeData\" from \"{connectionID}\" was ignored - concentrator data channel is set for auto-start.");
                        }
                        break;

                    case DeviceCommand.DisableRealTimeData:
                        // Only responding to stream control command if auto-start data channel is false
                        if (!AutoStartDataChannel)
                        {
                            StopDataChannel();
                            OnStatusMessage(MessageLevel.Info, $"Received request for \"DisableRealTimeData\" from \"{connectionID}\" - concentrator real-time data stream was stopped.");
                        }
                        else
                        {
                            OnStatusMessage(MessageLevel.Info, $"Request for \"DisableRealTimeData\" from \"{connectionID}\" was ignored - concentrator data channel is set for auto-start.");
                        }
                        break;

                    default:
                        OnStatusMessage(MessageLevel.Info, $"Request for \"{commandFrame.Command}\" from \"{connectionID}\" was ignored - device command is unsupported.");
                        break;
                    }
                }
                else
                {
                    OnStatusMessage(MessageLevel.Warning, $"Concentrator ID code validation failed for device command \"{commandFrame.Command}\" from \"{connectionID}\" - no action was taken.");
                }
            }
            catch (Exception ex)
            {
                OnProcessException(MessageLevel.Warning, new InvalidOperationException($"Remotely connected device \"{connectionID}\" sent an unrecognized data sequence to the concentrator, no action was taken. Exception details: {ex.Message}", ex));
            }
        }
Ejemplo n.º 4
0
 /// <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;
 }
Ejemplo n.º 5
0
        /// <summary>
        /// Creates a new IEEE C37.118 specific <see cref="DataFrame"/> for the given <paramref name="timestamp"/>.
        /// </summary>
        /// <param name="timestamp">Timestamp for new <see cref="IFrame"/> in <see cref="Ticks"/>.</param>
        /// <param name="configurationFrame">Associated <see cref="ConfigurationFrame1"/> for the new <see cref="DataFrame"/>.</param>
        /// <returns>New IEEE C37.118 <see cref="DataFrame"/> at given <paramref name="timestamp"/>.</returns>
        public static DataFrame CreateDataFrame(Ticks timestamp, ConfigurationFrame1 configurationFrame)
        {
            // We create a new IEEE C37.118 data frame based on current configuration frame
            DataFrame dataFrame = new DataFrame(timestamp, configurationFrame);
            DataCell dataCell;

            foreach (ConfigurationCell configurationCell in configurationFrame.Cells)
            {
                // Create a new IEEE C37.118 data cell (i.e., a PMU entry for this frame)
                dataCell = new DataCell(dataFrame, configurationCell, true);

                // Add data cell to the frame
                dataFrame.Cells.Add(dataCell);
            }

            return dataFrame;
        }