/* * 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 { /// /// /// Representation of the information found in a binary channel header. /// /// public class BinaryChannelHeader : Exceptional, IChannelHeader { /// /// /// "Magic Key" required for our binary file type. /// /// public static uint RequiredMagicKey => 0x2C36351F; public static uint CurrentVersionNumber => 0x04; /// /// Header version number required for our binary file type. /// public static List KnownHeaderVersionNumbers => new List(new uint[] { 0x01, 0x02, 0x03, 0x04 }); /// /// "Magic Key" relatively-UID for our binary file type. /// public uint MagicKey { get; set; } /// /// header version number for our binary file type. /// public uint HeaderVersionNumber { get; set; } /// /// Get/set offset of sample data start value. /// public ulong OffsetOfSampleDataStart { get; set; } /// /// Get/set number of samples. /// public ulong NumberOfSamples { get; set; } /// /// Get/set number of bits per sample. /// public uint NumberOfBitsPerSample { get; set; } /// /// Get/set signed sample indicator. /// public uint AreSamplesSigned { get; set; } /// /// Get/set sample rate value. /// public double SampleRate { get; set; } /// /// Get/set number of triggers. /// public ushort NumberOfTriggers { get; set; } /// /// Get/set the trigger sample numbers /// public ulong[] TriggerSampleNumbers { get; set; } /// /// 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 /// public int TriggerAdjustmentSamples { get; set; } /// /// Get/set pre test zero level counts. /// public int PreTestZeroLevelCounts { get; set; } /// /// 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 /// public int RemovedADC { get; set; } /// /// Get/set pre test diagnostics level counts. /// public int PreTestDiagnosticsLevelCounts { get; set; } /// /// the Analog Data Counts (ADC) when 0mV is injected /// (SLICE 1 can not inject 0mV and so will always return 0) /// public int ZeroMvInADC { get; set; } /// /// The average ADC over the Zero Window specified for the channel /// public int WindowAverageADC { get; set; } /// /// Initial Offset in ADC /// public int OriginalOffsetADC { get; set; } /// /// Get/set pre test noise percentage of full scale. /// public double PreTestNoisePercentageOfFullScale { get; set; } /// /// excitation on this channel /// with SLICE2 excitation can differ on each channel, so this gives a firm placeholder for information /// public double Excitation { get; set; } /// /// Get/set post test zero level counts. /// public int PostTestZeroLevelCounts { get; set; } /// /// Get/set post test diagnostics level counts. /// public int PostTestDiagnosticsLevelCounts { get; set; } /// /// Get/set data zero level counts. /// public int DataZeroLevelCounts { get; set; } /// /// Get/set scale factor MV. /// public double ScaleFactorMv { get; set; } /// /// Get/set sensitivity MV/EU /// public double MvPerEu { get; set; } /// /// Get/set EU field length (with terminator). /// public ushort EuFieldLengthWithTerminator { get; set; } /// /// Get/set engineering units. /// public char[] EngineeringUnit { get; set; } /// /// Get/set ISO code. /// 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; /// /// Calculate the CRC32 for this binary channe header. /// /// /// /// option enables/disables automatic stripping of EU padding. /// /// /// /// The CRC32 of the binary channel header. /// /// private uint CalculateCrc32(bool stripEuPadding, bool bKeepEuLength) { try { var data = new List(); 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); } } } /// /// Get The CRC for the current state of the header (autostrip padding from EU first). /// 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); } } } /// /// Get the CRC for the current state of the header. /// 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); } } } } } }