init
This commit is contained in:
@@ -0,0 +1,430 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user