431 lines
15 KiB
C#
431 lines
15 KiB
C#
/*
|
|
* SliceRaw.File.BinaryChannelHeader.cs
|
|
*
|
|
* Copyright © 2009
|
|
* Diversified Technical Systems, Inc.
|
|
* All Rights Reserved
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using DTS.Common.Utilities;
|
|
using DTS.Common.Utilities.Logging;
|
|
using DTS.Common.Utils;
|
|
|
|
namespace DTS.Serialization.SliceRaw
|
|
{
|
|
// *** see SliceRaw.File.cs ***
|
|
public partial class File
|
|
{ ///
|
|
/// <summary>
|
|
/// Representation of the information found in a binary channel header.
|
|
/// </summary>
|
|
///
|
|
public class BinaryChannelHeader
|
|
: Exceptional,
|
|
IChannelHeader
|
|
{ ///
|
|
/// <summary>
|
|
/// "Magic Key" required for our binary file type.
|
|
/// </summary>
|
|
///
|
|
public static uint RequiredMagicKey => 0x2C36351F;
|
|
|
|
public static uint CurrentVersionNumber => 0x04;
|
|
|
|
/// <summary>
|
|
/// Header version number required for our binary file type.
|
|
/// </summary>
|
|
public static List<uint> KnownHeaderVersionNumbers => new List<uint>(new uint[] { 0x01, 0x02, 0x03, 0x04 });
|
|
|
|
/// <summary>
|
|
/// "Magic Key" relatively-UID <see cref="UInt32"/> for our binary file type.
|
|
/// </summary>
|
|
public uint MagicKey
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// <see cref="UInt32"/> header version number for our binary file type.
|
|
/// </summary>
|
|
public uint HeaderVersionNumber
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set offset of sample data start value.
|
|
/// </summary>
|
|
public ulong OffsetOfSampleDataStart
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set number of samples.
|
|
/// </summary>
|
|
public ulong NumberOfSamples
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set number of bits per sample.
|
|
/// </summary>
|
|
public uint NumberOfBitsPerSample
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set signed sample indicator.
|
|
/// </summary>
|
|
public uint AreSamplesSigned
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set sample rate value.
|
|
/// </summary>
|
|
public double SampleRate
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set number of triggers.
|
|
/// </summary>
|
|
public ushort NumberOfTriggers
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set the trigger sample numbers
|
|
/// </summary>
|
|
public ulong[] TriggerSampleNumbers
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// the number of adjustment samples for the channel
|
|
/// The nature of level triggered is such that a number of qualification samples must pass before the
|
|
/// trigger is issued and then backdated to where the trigger started, which requires all other units
|
|
/// all be adjusted
|
|
/// </summary>
|
|
public int TriggerAdjustmentSamples
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
/// <summary>
|
|
/// Get/set pre test zero level counts.
|
|
/// </summary>
|
|
public int PreTestZeroLevelCounts
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// the number of Analog Data Counts (ADC) removed during any hardware
|
|
/// zeroing on the device.
|
|
/// In the case of SLICE the firmware will remove as much offset as possible and zero the DAC
|
|
/// </summary>
|
|
public int RemovedADC
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set pre test diagnostics level counts.
|
|
/// </summary>
|
|
public int PreTestDiagnosticsLevelCounts
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// the Analog Data Counts (ADC) when 0mV is injected
|
|
/// (SLICE 1 can not inject 0mV and so will always return 0)
|
|
/// </summary>
|
|
public int ZeroMvInADC
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The average ADC over the Zero Window specified for the channel
|
|
/// </summary>
|
|
public int WindowAverageADC
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initial Offset in ADC
|
|
/// </summary>
|
|
public int OriginalOffsetADC
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
/// <summary>
|
|
/// Get/set pre test noise percentage of full scale.
|
|
/// </summary>
|
|
public double PreTestNoisePercentageOfFullScale
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// excitation on this channel
|
|
/// with SLICE2 excitation can differ on each channel, so this gives a firm placeholder for information
|
|
/// </summary>
|
|
public double Excitation
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set post test zero level counts.
|
|
/// </summary>
|
|
public int PostTestZeroLevelCounts
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set post test diagnostics level counts.
|
|
/// </summary>
|
|
public int PostTestDiagnosticsLevelCounts
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set data zero level counts.
|
|
/// </summary>
|
|
public int DataZeroLevelCounts
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set scale factor MV.
|
|
/// </summary>
|
|
public double ScaleFactorMv
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set sensitivity MV/EU
|
|
/// </summary>
|
|
public double MvPerEu
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set EU field length (with terminator).
|
|
/// </summary>
|
|
public ushort EuFieldLengthWithTerminator
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set engineering units.
|
|
/// </summary>
|
|
public char[] EngineeringUnit
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set ISO code.
|
|
/// </summary>
|
|
public char[] IsoCode
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
private const int HEADER_VERSION_REMOVEDADC = 2;
|
|
private const int HEADER_VERSION_3 = 3;
|
|
private const int HEADER_VERSION_4 = 4;
|
|
|
|
/// <summary>
|
|
/// Calculate the CRC32 for this binary channe header.
|
|
/// </summary>
|
|
///
|
|
/// <param name="stripEuPadding">
|
|
/// <see cref="bool"/> option enables/disables automatic stripping of EU padding.
|
|
/// </param>
|
|
///
|
|
/// <returns>
|
|
/// The CRC32 of the binary channel header.
|
|
/// </returns>
|
|
///
|
|
private uint CalculateCrc32(bool stripEuPadding, bool bKeepEuLength)
|
|
{
|
|
try
|
|
{
|
|
var data = new List<byte>();
|
|
|
|
data.AddRange(BitConverter.GetBytes(MagicKey));
|
|
data.AddRange(BitConverter.GetBytes(HeaderVersionNumber));
|
|
data.AddRange(BitConverter.GetBytes(OffsetOfSampleDataStart));
|
|
data.AddRange(BitConverter.GetBytes(NumberOfSamples));
|
|
data.AddRange(BitConverter.GetBytes(NumberOfBitsPerSample));
|
|
data.AddRange(BitConverter.GetBytes(NumberOfSamples));
|
|
data.AddRange(BitConverter.GetBytes(AreSamplesSigned));
|
|
data.AddRange(BitConverter.GetBytes(SampleRate));
|
|
data.AddRange(BitConverter.GetBytes(NumberOfTriggers));
|
|
|
|
for (var i = 0; i < TriggerSampleNumbers.Length; i++)
|
|
data.AddRange(BitConverter.GetBytes(TriggerSampleNumbers[i]));
|
|
|
|
data.AddRange(BitConverter.GetBytes(PreTestZeroLevelCounts));
|
|
//data.AddRange(BitConverter.GetBytes(PreTestZeroLevelMv));
|
|
if (HeaderVersionNumber >= HEADER_VERSION_REMOVEDADC) { data.AddRange(BitConverter.GetBytes(RemovedADC)); }
|
|
if (HeaderVersionNumber >= HEADER_VERSION_3)
|
|
{
|
|
data.AddRange(BitConverter.GetBytes(Excitation));
|
|
data.AddRange(BitConverter.GetBytes(TriggerAdjustmentSamples));
|
|
data.AddRange(BitConverter.GetBytes(ZeroMvInADC));
|
|
data.AddRange(BitConverter.GetBytes(OriginalOffsetADC));
|
|
}
|
|
if (HeaderVersionNumber >= HEADER_VERSION_4)
|
|
{
|
|
data.AddRange(BitConverter.GetBytes(WindowAverageADC));
|
|
}
|
|
data.AddRange(BitConverter.GetBytes(PreTestDiagnosticsLevelCounts));
|
|
data.AddRange(BitConverter.GetBytes(PreTestNoisePercentageOfFullScale));
|
|
data.AddRange(BitConverter.GetBytes(PostTestZeroLevelCounts));
|
|
data.AddRange(BitConverter.GetBytes(PostTestDiagnosticsLevelCounts));
|
|
data.AddRange(BitConverter.GetBytes(DataZeroLevelCounts));
|
|
data.AddRange(BitConverter.GetBytes(ScaleFactorMv));
|
|
data.AddRange(BitConverter.GetBytes(MvPerEu));
|
|
|
|
// Some data sets have an erroneous EuFieldLengthWithTerminator value that's +1 what it should be,
|
|
// so we'll want to make an allowance for these ones too.
|
|
var plusOneFieldLengthBugErrorPresent = EuFieldLengthWithTerminator > EngineeringUnit.Length + 1;
|
|
if (bKeepEuLength) { plusOneFieldLengthBugErrorPresent = true; }
|
|
|
|
var padAdjustedEu = new string(EngineeringUnit).Trim().ToCharArray();
|
|
if (!stripEuPadding)
|
|
{ //
|
|
// If we want to calculate the CRC of the header with leading/trailing
|
|
// whitespace intact/added.
|
|
//
|
|
if (padAdjustedEu.Length % 2 != 0)
|
|
padAdjustedEu = (new string(padAdjustedEu) + ' ').ToCharArray();
|
|
}
|
|
|
|
|
|
var euBA = Encoding.UTF8.GetBytes(padAdjustedEu);
|
|
var euFieldLength = plusOneFieldLengthBugErrorPresent ? EuFieldLengthWithTerminator : (ushort)(euBA.Length + 1);
|
|
data.AddRange(BitConverter.GetBytes(euFieldLength));
|
|
|
|
for (var i = 0; i < padAdjustedEu.Length; i++)
|
|
data.AddRange(BitConverter.GetBytes(padAdjustedEu[i]));
|
|
|
|
for (var i = 0; i < IsoCode.Length; i++)
|
|
data.AddRange(BitConverter.GetBytes(IsoCode[i]));
|
|
|
|
// We need to pad the offset so DIAdem .dat file word alignment will work. DIAdem .dat files reference the .chn files directly.
|
|
if (data.Count % 2 > 0) data.Add(0x0);
|
|
var byteDataArray = data.ToArray();
|
|
//APILogger.Log($"[DTM]: data array for CRC: {BitConverter.ToString(byteDataArray)}");
|
|
ushort crc = 0xFFFF;
|
|
for (var i = 0; i < data.Count; i += 2)
|
|
crc = Utils.Math_DoCRC16Step(BitConverter.ToUInt16(byteDataArray, i), crc);
|
|
//APILogger.Log($"[DTM]: crc {crc}");
|
|
return crc;
|
|
}
|
|
|
|
catch (System.Exception ex)
|
|
{
|
|
throw new Exception("encountered problem calculating CRC 32", ex);
|
|
}
|
|
}
|
|
public uint UnpaddedEuStringPaddedEuLengthCrc32
|
|
{
|
|
get
|
|
{
|
|
try { return CalculateCrc32(true, true); }
|
|
catch (System.Exception ex)
|
|
{
|
|
throw new Exception("encountered problem getting CRC32 for binary header channel with unpadded EU string and padded EU Length", ex);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Get The CRC for the current state of the header (autostrip padding from EU first).
|
|
/// </summary>
|
|
public uint UnpaddedEuCrc32
|
|
{
|
|
get
|
|
{
|
|
try
|
|
{
|
|
return CalculateCrc32(true, false);
|
|
}
|
|
|
|
catch (System.Exception ex)
|
|
{
|
|
throw new Exception("encountered problem getting CRC32 for binary header channel with unpadded EU string", ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the CRC for the current state of the header.
|
|
/// </summary>
|
|
public uint Crc32
|
|
{
|
|
get
|
|
{
|
|
try
|
|
{
|
|
return CalculateCrc32(false, false);
|
|
}
|
|
|
|
catch (System.Exception ex)
|
|
{
|
|
throw new Exception("encountered problem generating CRC for binary channel header information", ex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|