/// <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>
protected override int ParseBodyImage(byte[] buffer, int startIndex, int length)
{
ConfigurationCell configCell = ConfigurationCell;
ConfigurationFrame configFrame = configCell.Parent;
ProtocolVersion protocolVersion = configFrame.CommonHeader.ProtocolVersion;
IPhasorValue phasorValue;
IDigitalValue digitalValue;
int parsedLength, index = startIndex;
if (protocolVersion == ProtocolVersion.M)
{
// Parse out optional STATUS2 flags
if (configFrame.Status2Included)
{
m_status2Flags = buffer[index];
index++;
}
else
{
m_status2Flags = 0;
}
// We interpret status bytes together as one word (matches other protocols this way)
base.StatusFlags = Word.MakeWord((byte)Status1Flags, m_status2Flags);
}
else
{
// Read sample number for G protocol
m_sampleNumber = BigEndian.ToUInt16(buffer, index);
index += 2;
}
// Parse out time tag
if (configFrame.TimestampIncluded)
{
m_clockStatusFlags = (ClockStatusFlags)buffer[index];
index += 1;
ushort day = BinaryCodedDecimal.Decode(BigEndian.ToUInt16(buffer, index));
byte hours = BinaryCodedDecimal.Decode(buffer[index + 2]);
byte minutes = BinaryCodedDecimal.Decode(buffer[index + 3]);
byte seconds = BinaryCodedDecimal.Decode(buffer[index + 4]);
double timebase = 2880.0D;
index += 5;
// Read sample number for M protocol
if (protocolVersion == ProtocolVersion.M)
{
m_sampleNumber = BigEndian.ToUInt16(buffer, index + 5);
timebase = 719.0D;
index += 2;
}
// TODO: Think about how to handle year change with floating clock...
// Calculate timestamp
Parent.Timestamp = new DateTime(DateTime.UtcNow.Year, 1, 1).AddDays(day - 1).AddHours(hours).AddMinutes(minutes).AddSeconds(seconds + m_sampleNumber / timebase);
}
else
{
Parent.Timestamp = DateTime.UtcNow.Ticks;
SynchronizationIsValid = false;
m_sampleNumber = BigEndian.ToUInt16(buffer, index);
index += 2;
}
// Parse out first five phasor values (1 - 5)
int phasorIndex = 0;
// Phasor 1 (always present)
phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
PhasorValues.Add(phasorValue);
index += parsedLength;
if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor2Enabled) == OnlineDataFormatFlags.Phasor2Enabled)
{
// Phasor 2
phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
PhasorValues.Add(phasorValue);
index += parsedLength;
}
if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor3Enabled) == OnlineDataFormatFlags.Phasor3Enabled)
{
// Phasor 3
phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
PhasorValues.Add(phasorValue);
index += parsedLength;
}
if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor4Enabled) == OnlineDataFormatFlags.Phasor4Enabled)
{
// Phasor 4
phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
PhasorValues.Add(phasorValue);
index += parsedLength;
}
if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor5Enabled) == OnlineDataFormatFlags.Phasor5Enabled)
{
// Phasor 5
phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
PhasorValues.Add(phasorValue);
index += parsedLength;
}
// For 1690M format the frequency, reference phasor, dF/dt and first digital follow phasors 1-5
if (protocolVersion == ProtocolVersion.M)
{
// Parse out frequency value
FrequencyValue = Macrodyne.FrequencyValue.CreateNewValue(this, configCell.FrequencyDefinition, buffer, index, out parsedLength);
index += parsedLength;
// Parse reference phasor information
if (configFrame.ReferenceIncluded)
{
m_referenceSampleNumber = BigEndian.ToUInt16(buffer, index);
m_referencePhasor = PhasorValue.CreateNewValue(this, new PhasorDefinition(null, "Reference Phasor", PhasorType.Voltage, null), buffer, index, out parsedLength) as PhasorValue;
index += 6;
}
// Parse first digital value
if (configFrame.Digital1Included)
{
digitalValue = DigitalValue.CreateNewValue(this, configCell.DigitalDefinitions[0], buffer, index, out parsedLength);
DigitalValues.Add(digitalValue);
index += parsedLength;
}
}
// Parse out next five phasor values (6 - 10)
if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor6Enabled) == OnlineDataFormatFlags.Phasor6Enabled)
{
// Phasor 6
phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
PhasorValues.Add(phasorValue);
index += parsedLength;
}
if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor7Enabled) == OnlineDataFormatFlags.Phasor7Enabled)
{
// Phasor 7
phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
PhasorValues.Add(phasorValue);
index += parsedLength;
}
if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor8Enabled) == OnlineDataFormatFlags.Phasor8Enabled)
{
// Phasor 8
phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
PhasorValues.Add(phasorValue);
index += parsedLength;
}
if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor9Enabled) == OnlineDataFormatFlags.Phasor9Enabled)
{
// Phasor 9
phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
PhasorValues.Add(phasorValue);
index += parsedLength;
}
if ((configFrame.OnlineDataFormatFlags & OnlineDataFormatFlags.Phasor10Enabled) == OnlineDataFormatFlags.Phasor10Enabled)
{
// Phasor 10
phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
PhasorValues.Add(phasorValue);
index += parsedLength;
}
// For 1690G format the channel phasors, reference phasor, frequency, dF/dt and digitals follow phasors 1-10
if (protocolVersion == ProtocolVersion.G)
{
// Technically 30 more possible channel phasors can be defined
for (int i = phasorIndex; i < ConfigurationCell.PhasorDefinitions.Count; i++)
{
phasorValue = PhasorValue.CreateNewValue(this, configCell.PhasorDefinitions[phasorIndex++], buffer, index, out parsedLength);
PhasorValues.Add(phasorValue);
index += parsedLength;
}
// Parse reference phasor information
if (configFrame.ReferenceIncluded)
{
m_referencePhasor = PhasorValue.CreateNewValue(this, new PhasorDefinition(null, "Reference Phasor", PhasorType.Voltage, null), buffer, index, out parsedLength) as PhasorValue;
index += parsedLength;
}
// Parse out frequency value
FrequencyValue = Macrodyne.FrequencyValue.CreateNewValue(this, configCell.FrequencyDefinition, buffer, index, out parsedLength);
index += parsedLength;
// Parse first digital value
if (configFrame.Digital1Included)
{
digitalValue = DigitalValue.CreateNewValue(this, configCell.DigitalDefinitions[0], buffer, index, out parsedLength);
DigitalValues.Add(digitalValue);
index += parsedLength;
}
}
// Parse second digital value
if (configFrame.Digital2Included)
{
digitalValue = DigitalValue.CreateNewValue(this, configCell.DigitalDefinitions[configCell.DigitalDefinitions.Count - 1], buffer, index, out parsedLength);
DigitalValues.Add(digitalValue);
index += parsedLength;
}
// Return total parsed length
return(index - startIndex);
}