//******************************************************************************************************
// CommonFrameHeader.cs - Gbtc
//
// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://www.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 03/20/2009 - J. Ritchie Carroll
// Generated original version of source code.
// 09/15/2009 - Stephen C. Wills
// Added new header and license agreement.
// 12/17/2012 - Starlynn Danyelle Gilliam
// Modified Header.
//
//******************************************************************************************************
using System;
using System.Text;
using GSF.Parsing;
namespace GSF.PhasorProtocols.FNET
{
///
/// Represents the common header for a F-NET frame of data.
///
///
/// Because of its simplicity, all F-NET parsing is handled in the constructor of
/// this class. Subsequently all parsed data is available as an array of strings
/// where needed.
///
public class CommonFrameHeader : CommonHeaderBase
{
#region [ Constructors ]
///
/// Creates a new from given .
///
/// Buffer that contains data to parse.
/// Start index into buffer where valid data begins.
/// Length of valid data in .
public CommonFrameHeader(byte[] buffer, int startIndex, int length)
{
// Validate F-NET data image
if (buffer[startIndex] != Common.StartByte)
throw new InvalidOperationException($"Bad data stream, expected start byte 0x01 as first byte in F-NET frame, got 0x{buffer[startIndex].ToString("X").PadLeft(2, '0')}");
int endIndex = -1, stopIndex = Array.IndexOf(buffer, Common.EndByte, startIndex, length);
if (stopIndex < 0)
throw new InvalidOperationException("Bad data stream, did not find stop byte 0x00 in F-NET frame");
for (int i = stopIndex; i < length; i++)
{
// We continue to scan through duplicate end bytes (nulls)
if (buffer[i] == Common.EndByte)
endIndex = i;
else if (endIndex >= 0)
break;
}
if (endIndex > -1)
{
// Parse F-NET data frame into individual fields separated by spaces
DataElements = Encoding.ASCII.GetString(buffer, startIndex + 1, stopIndex - startIndex - 1).RemoveDuplicateWhiteSpace().Trim().Split(' ');
// Make sure all the needed data elements exist (could be a bad frame)
if (DataElements.Length != 8)
throw new InvalidOperationException($"Bad data stream, invalid number of data elements encountered in F-NET data stream line: \"{Encoding.ASCII.GetString(buffer, startIndex + 1, stopIndex - startIndex - 1).RemoveControlCharacters().Trim()}\". Got {DataElements.Length} elements, expected 8.");
// Remove any extraneous spaces or control characters that may have been injected by the source device
for (int i = 0; i < DataElements.Length; i++)
DataElements[i] = DataElements[i].RemoveWhiteSpace().RemoveControlCharacters();
// Calculate total bytes parsed including start and stop bytes
ParsedLength = endIndex - startIndex + 1;
}
}
#endregion
#region [ Properties ]
///
/// Gets F-NET data elements parsed during construction.
///
public string[] DataElements { get; }
///
/// Gets length of data parsed during construction.
///
public int ParsedLength { get; }
#endregion
}
}