예제 #1
0
        /// <summary>
        /// Parses a common header instance that implements <see cref="ICommonHeader{TTypeIdentifier}"/> for the output type represented
        /// in the binary image.
        /// </summary>
        /// <param name="buffer">Buffer containing data to parse.</param>
        /// <param name="offset">Offset index into buffer that represents where to start parsing.</param>
        /// <param name="length">Maximum length of valid data from offset.</param>
        /// <returns>The <see cref="ICommonHeader{TTypeIdentifier}"/> which includes a type ID for the <see cref="Type"/> to be parsed.</returns>
        /// <remarks>
        /// <para>
        /// Derived classes need to provide a common header instance (i.e., class that implements <see cref="ICommonHeader{TTypeIdentifier}"/>)
        /// for the output types; this will primarily include an ID of the <see cref="Type"/> that the data image represents.  This parsing is
        /// only for common header information, actual parsing will be handled by output type via its <see cref="ISupportBinaryImage.ParseBinaryImage"/>
        /// method. This header image should also be used to add needed complex state information about the output type being parsed if needed.
        /// </para>
        /// <para>
        /// If there is not enough buffer available to parse common header (as determined by <paramref name="length"/>), return null.  Also, if
        /// the protocol allows frame length to be determined at the time common header is being parsed and there is not enough buffer to parse
        /// the entire frame, it will be optimal to prevent further parsing by returning null.
        /// </para>
        /// </remarks>
        protected override ICommonHeader <int> ParseCommonHeader(byte[] buffer, int offset, int length)
        {
            int scanLength;

            // Calculate a maximum reasonable scan size for the buffer
            if (length > Common.MaximumPracticalFrameSize)
            {
                scanLength = Common.MaximumPracticalFrameSize;
            }
            else
            {
                scanLength = length;
            }

            // See if there is enough data in the buffer to parse the common frame header by scanning for the F-NET termination byte
            if (scanLength > 0 && Array.IndexOf(buffer, Common.EndByte, offset, scanLength) >= 0)
            {
                // Pre-parse F-NET data row...
                CommonFrameHeader parsedFrameHeader = new CommonFrameHeader(buffer, offset, length);

                int parsedLength = parsedFrameHeader.ParsedLength;

                if (parsedLength > 0)
                {
                    // Create configuration frame if it doesn't exist
                    if (m_configurationFrame == null)
                    {
                        string[] data = parsedFrameHeader.DataElements;

                        // Create virtual configuration frame
                        m_configurationFrame = new ConfigurationFrame(ushort.Parse(data[Element.UnitID]), DateTime.UtcNow.Ticks, m_frameRate, m_nominalFrequency, m_timeOffset, m_stationName);

                        // Notify clients of new configuration frame
                        OnReceivedChannelFrame(m_configurationFrame);
                    }

                    if (m_configurationFrame != null)
                    {
                        // Assign common header and data frame parsing state
                        parsedFrameHeader.State = new DataFrameParsingState(parsedLength, m_configurationFrame, DataCell.CreateNewCell, TrustHeaderLength, ValidateDataFrameCheckSum);

                        // Expose the frame buffer image in case client needs this data for any reason
                        OnReceivedFrameBufferImage(FundamentalFrameType.DataFrame, buffer, offset, parsedLength);

                        return(parsedFrameHeader);
                    }
                }
            }
            else if (scanLength == Common.MaximumPracticalFrameSize)
            {
                throw new InvalidOperationException(string.Format("Possible bad F-NET data stream, scanned {0} bytes without finding an expected termination byte 0x0", Common.MaximumPracticalFrameSize));
            }

            return(null);
        }
예제 #2
0
        /// <summary>
        /// Parses the binary body image.
        /// </summary>
        /// <param name="buffer">Binary image to parse.</param>
        /// <param name="startIndex">Start index into <paramref name="buffer"/> to begin parsing.</param>
        /// <param name="length">Length of valid data within <paramref name="buffer"/>.</param>
        /// <returns>The length of the data that was parsed.</returns>
        /// <remarks>
        /// The longitude, latitude and number of satellites arrive at the top of minute in F-NET data as the analog
        /// data in a single row, each on their own row, as sample 1, 2, and 3 respectively.
        /// </remarks>
        protected override int ParseBodyImage(byte[] buffer, int startIndex, int length)
        {
            DataFrame         parent       = Parent;
            CommonFrameHeader commonHeader = parent.CommonHeader;

            string[]          data = commonHeader.DataElements;
            ConfigurationCell configurationCell = ConfigurationCell;
            uint sampleIndex;

            // Attempt to parse sample index
            if (uint.TryParse(data[Element.SampleIndex], out sampleIndex))
            {
                parent.SampleIndex = sampleIndex;

                // Get timestamp of data record
                parent.Timestamp = configurationCell.TimeOffset + ParseTimestamp(data[Element.Date], data[Element.Time], parent.SampleIndex, configurationCell.FrameRate);

                // Parse out first analog value (can be long/lat at top of minute)
                m_analogValue = double.Parse(data[Element.Analog]);

                if (data[Element.Time].Length >= 7 && int.Parse(data[Element.Time].Substring(4, 2)) == 0)
                {
                    switch (parent.SampleIndex)
                    {
                    case 1:
                        configurationCell.Latitude = m_analogValue;
                        break;

                    case 2:
                        configurationCell.Longitude = m_analogValue;
                        break;

                    case 3:
                        configurationCell.NumberOfSatellites = (int)m_analogValue;
                        break;
                    }
                }

                // Update (or create) frequency value
                double frequency = double.Parse(data[Element.Frequency]);

                if (FrequencyValue != null)
                {
                    FrequencyValue.Frequency = frequency;
                }
                else
                {
                    FrequencyValue = new FrequencyValue(this, configurationCell.FrequencyDefinition as FrequencyDefinition, frequency, 0.0D);
                }

                // Update (or create) phasor value
                Angle       angle     = double.Parse(data[Element.Angle]);
                double      magnitude = double.Parse(data[Element.Voltage]);
                PhasorValue phasor    = null;

                if (PhasorValues.Count > 0)
                {
                    phasor = PhasorValues[0] as PhasorValue;
                }

                if (phasor != null)
                {
                    phasor.Angle     = angle;
                    phasor.Magnitude = magnitude;
                }
                else
                {
                    phasor = new PhasorValue(this, configurationCell.PhasorDefinitions[0] as PhasorDefinition, angle, magnitude);
                    PhasorValues.Add(phasor);
                }
            }

            return(commonHeader.ParsedLength);
        }