This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,321 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using DTS.Common.DAS.Concepts;
using DTS.Common.Utilities;
using DTS.Common.Enums.Sensors;
namespace DTS.Serialization.TDM
{
public class ChannelData
{
public void GenerateChannelData(Writer writer, System.IO.TextWriter tw, bool bFiltered, double start, double end, UInt16 subSampleInterval,
out ulong practicalNumSamples, out ulong numSamples, out Test test, out DataScaler[] scalers, out double sampleRate,
out List<short[]> ChannelDataUnFiltered, out List<double[]> ChannelDataFiltered, out int preTriggerSamples)
{
test = writer.Test;
var maxRate = test.Channels.Select(ch => ch.ParentModule.SampleRateHz).Max();
sampleRate = maxRate;
var distinctRates = test.Channels.Select(ch => ch.ParentModule.SampleRateHz).Distinct().ToArray();
var testChannels = new List<Test.Module.Channel>(test.Channels);
//numSamples = Convert.ToUInt64((from ch in testChannels select ch.PersistentChannelInfo.Data.Length).Min());
numSamples = Convert.ToUInt64(testChannels.Select(ch => ch.PersistentChannelInfo.Data.Length * (maxRate / ch.ParentModule.SampleRateHz)).Min());
preTriggerSamples = 0;
var originalNumSamples = numSamples;
//note we can have extra data, so numSamples doesn't always mean number of samples
//instead use practical number of samples to be artificially constrained number of samples and number of samples to mean
//either, as the existing code did.
//7757 TTS sub sample was not working. exported data is too much.
practicalNumSamples = Convert.ToUInt64((end - start) * sampleRate + 1);
ChannelDataUnFiltered = new List<short[]>();
ChannelDataFiltered = new List<double[]>();
scalers = new DataScaler[testChannels.Count];
if (1 < subSampleInterval)
{
if (distinctRates.Length > 1) { throw new System.Exception("we are both super sampling and subsampling in this export."); }
for (var iChannel = 0; iChannel < test.Channels.Count; iChannel++)
{
var rate = Convert.ToInt32(sampleRate / test.Channels[iChannel].ParentModule.SampleRateHz);
if (0 == iChannel)
{
practicalNumSamples = Convert.ToUInt64(Math.Ceiling(practicalNumSamples / (double)subSampleInterval));
}
if (true == bFiltered)
{
var SubSample = new NHTSASubSample<double>();
SubSample.data = writer.FilteredData[iChannel].Data;
var preTriggerRequested = (ulong)Math.Max(0, (-1 * (int)Math.Truncate(start * sampleRate))); //If start is > 0, it's not pre-trigger, so return 0
SubSample.preTriggerSamples = Math.Min((test.Modules[0].TriggerSampleNumbers[0] - test.Modules[0].StartRecordSampleNumber), preTriggerRequested);
SubSample.sampleRate = sampleRate;
SubSample.subSampleInterval = subSampleInterval;
SubSample.SubSample();
if (iChannel >= ChannelDataFiltered.Count)
{
ChannelDataFiltered.Add(SubSample.data);
}
else
{
ChannelDataFiltered[iChannel] = SubSample.data;
}
//writer.FilteredData[iChannel].Data = SubSample.data;
//ChannelList[iChannel].IsSubsampled = true; // I don't think anyone will consume this, but for completeness.
numSamples = Math.Min(numSamples, (ulong)SubSample.data.Length);
//note we have extra data, so numSamples is accurate, however gives us more data than we want ...
//7757 TTS sub sample was not working. exported data is too much.
if (SubSample.iNpre > 0)
{
preTriggerSamples = SubSample.iNpre + 1;
}
}
else
{
var SubSample = new NHTSASubSample<short>();
SubSample.data = test.Channels[iChannel].PersistentChannelInfo.Data;
var preTriggerRequested = (ulong)Math.Max(0, (-1 * (int)Math.Truncate(start * sampleRate))); //If start is > 0, it's not pre-trigger, so return 0
SubSample.preTriggerSamples = Math.Min((test.Modules[0].TriggerSampleNumbers[0] - test.Modules[0].StartRecordSampleNumber), preTriggerRequested);
SubSample.sampleRate = sampleRate;
SubSample.subSampleInterval = subSampleInterval;
SubSample.SubSample();
if (iChannel >= ChannelDataUnFiltered.Count)
{
ChannelDataUnFiltered.Add(SubSample.data);
}
else
{
ChannelDataUnFiltered[iChannel] = SubSample.data;
}
//ChannelList[iChannel].IsSubsampled = true; // I don't think anyone will consume this, but for completeness.
numSamples = Math.Min(numSamples, (ulong)SubSample.data.Length);
//note we have extra data, so numSamples is accurate, however gives us more data than we want ...
//7757 TTS sub sample was not working. exported data is too much.
if (SubSample.iNpre > 0)
{
preTriggerSamples = SubSample.iNpre + 1;
}
}
}
sampleRate = sampleRate / subSampleInterval;
}
else
{
var TotalSamples = ulong.MaxValue;
//the lowest common start in samples from t0 that all modules have
var minStart = double.MinValue;
foreach (var module in test.Modules)
{
//Don't process Slice6DB modules that were created to store Temperature values from Arm checklist
if (module.Channels.Count <= 0) continue;
TotalSamples = Math.Min(TotalSamples, module.NumberOfSamples);
double mStart = module.TriggerSampleNumbers[0] - module.StartRecordSampleNumber;
minStart = Math.Max(minStart, mStart);
}
var startSample = -1D * start * test.Modules[0].SampleRateHz;
//we don't have enough data, adjust appropriately
if (startSample > minStart) { startSample = minStart; }
preTriggerSamples = (int)Math.Truncate(startSample);
}
}
public void WriteChannelData(Writer writer, System.IO.TextWriter tw, bool bFiltered, double start, double end, UInt16 subSampleInterval,
ulong practicalNumSamples, ulong numSamples, Test test, DataScaler[] scalers, double sampleRate, List<short[]> ChannelDataUnFiltered,
List<double[]> ChannelDataFiltered)
{
var bSubSampled = subSampleInterval > 1;
// var maxSamples = (ulong)(bFiltered ? writer.FilteredData[0].Data.Length : (test.Channels[0] as Test.Module.AnalogInputChannel).PersistentChannelInfo.Data.Length);
var maxSamples = 0UL;
if (bFiltered)
{
maxSamples = Convert.ToUInt64(writer.FilteredData.Select(ch => ch.Data.Length).Max());
}
else
{
maxSamples = Convert.ToUInt64(test.Channels.Select(ch => ch.PersistentChannelInfo.Data.Length).Max());
}
if (bSubSampled)
{
maxSamples = Convert.ToUInt64(bFiltered ? ChannelDataFiltered[0].Length : ChannelDataUnFiltered[0].Length);
}
var channelList = new List<Test.Module.Channel>(test.Channels);
//var parentModule = (channelList[0] as Test.Module.AnalogInputChannel).ParentModule;
//var moduleSampleRate = (double)parentModule.SampleRateHz;
//var moduleTriggerSampleNumber = (double)parentModule.TriggerSampleNumbers[0];
//var moduleStartRecordSampleNumber = (double)parentModule.StartRecordSampleNumber;
for (ulong i = 0; i < practicalNumSamples && i < numSamples; i++)
{
if (i > 0 && 0 == i % writer.IncrementLevel)
{
writer.IncrementDone((double)i / practicalNumSamples * 100);
}
// Need to be a little defensive about the end of the array for the sub-sample case where dIndex might be non-integer and then rounded up.
//var dIndex = (start * moduleSampleRate + moduleTriggerSampleNumber) / subSampleInterval + Convert.ToDouble(i);
//we now have dIndex = the start index in terms of sample count, we want to translate it to an index in our data
//dIndex = dIndex - moduleStartRecordSampleNumber / subSampleInterval;
//if (dIndex > Convert.ToDouble(maxSamples - 1))
//{
// break;
//}
var time = start + (i / sampleRate);
tw.Write(time.ToString("e5", CultureInfo.InvariantCulture));
tw.Write(",");
var ChannelCount = channelList.Count;
for (var iChannel = 0; iChannel < ChannelCount; iChannel++)
{
var channel = channelList[iChannel] as Test.Module.AnalogInputChannel;
DataScaler scaler = null;
if (channel.IsSquibVoltage())
{
continue;
}
if (iChannel < scalers.Length) { scaler = scalers[iChannel]; }
if (null == scaler)
{
scaler = new DataScaler();
scaler.IsInverted = channel.IsInverted;//channel is DTS.Common.DAS.Concepts.DAS.Channel.IInversionAware ? (channel as DTS.Common.DAS.Concepts.DAS.Channel.IInversionAware).IsInverted : false;
scaler.SetLinearizationFormula(channel.LinearizationFormula);
scaler.SetScaleFactorMv(channel.Data.ScaleFactorMv);
scaler.SetScaleFactorEU(channel.Data.ScaleFactorEU);
scaler.SetUseEUScaleFactors(channel.Data.UseEUScaleFactors);
var analogChannel = channel;
if (channel is Test.Module.AnalogInputChannel)
{
scaler.IEPE = analogChannel.Bridge == SensorConstants.BridgeType.IEPE;
scaler.Digital = analogChannel.Bridge == SensorConstants.BridgeType.DigitalInput;
scaler.SetDigitalMultiplier(analogChannel.DigitalMultiplier);
//FB 13414 Apply EU multiplier in TTS export.
scaler.Multiplier = analogChannel.Multiplier;
//FB 16222 Apply EU Offset in TTS export.
scaler.UserOffsetEU = analogChannel.UserOffsetEU;
scaler.DigitalMode = analogChannel.DigitalMode;
}
scaler.SetLinearizationFormula(channel.LinearizationFormula);
scaler.SetMvPerEu(channel.Data.MvPerEu);
scaler.UnitConversion = channel.UnitConversion;
scaler.BasedOnOutputAtCapacity = channel.AtCapacity;
scaler.CapacityOutputIsBasedOn = channel.CapacityOutputIsBasedOn;
scaler.SensitivityUnits = channel.SensitivityUnits;
try
{
scaler.SetInitialOffset(analogChannel.InitialOffset);
scaler.ZeroMethodType = analogChannel.ZeroMethod;
if (analogChannel.RemoveOffset) { scaler.SetRemovedADC(channel.RemovedADC); }
else { scaler.SetRemovedADC(0); }
scaler.SetDataZeroLevelADC(channel.DataZeroLevelAdc);
scaler.SetZeroMvInADC(channel.ZeroMvInADC);
try { scaler.SetWindowAverageADC(channel.WindowAverageADC); }
catch (Exception) { }
}
catch (Exception) { }
scaler.NominalExcitationVoltage = analogChannel.ExcitationVoltage;
if (analogChannel.MeasuredExcitationVoltageValid)
{
try { scaler.MeasuredExcitationVoltage = analogChannel.MeasuredExcitationVoltage; }
catch { };
}
if (analogChannel.FactoryExcitationVoltageValid)
{
try { scaler.FactoryExcitationVoltage = analogChannel.FactoryExcitationVoltage; }
catch { };
}
scaler.SetInitialOffset(analogChannel.InitialOffset);
scaler.ZeroMethodType = analogChannel.ZeroMethod;
scaler.ProportionalToExcitation = channel.ProportionalToExcitation;
scalers[iChannel] = scaler;
}
var dStartTime = (double)channel.ParentModule.StartRecordSampleNumber / channel.ParentModule.SampleRateHz;
if (channel.ParentModule.TriggerSampleNumbers.Count > 0)
{
dStartTime -= (double)channel.ParentModule.TriggerSampleNumbers[0] / channel.ParentModule.SampleRateHz;
}
var rate = Convert.ToInt32(Math.Ceiling(sampleRate / channel.ParentModule.SampleRateHz));
var channelOffsetStart = (int)((dStartTime - start) * channel.ParentModule.SampleRateHz);
var indexAtCurrentTime = ((double)i - channelOffsetStart) / rate;
var thisChannelsIndexAtCurrentTime = Convert.ToInt32(Math.Floor(indexAtCurrentTime));
var step = Convert.ToInt32(Math.Ceiling(indexAtCurrentTime) - thisChannelsIndexAtCurrentTime);
var d = double.NaN;
if (thisChannelsIndexAtCurrentTime >= 0)
{
if (bFiltered)
{
if (bSubSampled)
{
d = scaler.GetEU(ChannelDataFiltered[iChannel][Convert.ToUInt64(thisChannelsIndexAtCurrentTime)]);
}
else
{
var increment = 0D;
var adc = writer.FilteredData[iChannel].Data[Convert.ToUInt64(thisChannelsIndexAtCurrentTime)];
if ((thisChannelsIndexAtCurrentTime + 1) < writer.FilteredData[iChannel].Data.Length)
{
increment = (writer.FilteredData[iChannel].Data[thisChannelsIndexAtCurrentTime + 1] - adc) / rate;
}
else
{
increment = (adc - writer.FilteredData[iChannel].Data[thisChannelsIndexAtCurrentTime - 1]) / rate;
}
d = scaler.GetEU(adc + increment * step);
}
}
else
{
if (bSubSampled)
{
d = scaler.GetEU(ChannelDataUnFiltered[iChannel][Convert.ToInt64(thisChannelsIndexAtCurrentTime)]);
}
else
{
var increment = 0D;
var adc = channel.PersistentChannelInfo.Data[Convert.ToUInt64(thisChannelsIndexAtCurrentTime)];
if ((thisChannelsIndexAtCurrentTime + 1) < channel.PersistentChannelInfo.Data.Length)
{
increment = (channel.PersistentChannelInfo.Data[thisChannelsIndexAtCurrentTime + 1] - adc) / rate;
}
else
{
increment = (adc - channel.PersistentChannelInfo.Data[thisChannelsIndexAtCurrentTime - 1]) / rate;
}
d = scaler.GetEU(adc + increment * step);
}
}
}
tw.Write((d * channel.Sensitivity).ToString("e4", CultureInfo.InvariantCulture));
tw.Write(",");
}
tw.WriteLine();
}
tw.Flush();
}
}
}

View File

@@ -0,0 +1,273 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using DTS.Common.DAS.Concepts;
using DTS.Common.Enums.Sensors;
using DTS.Common.Utilities;
using DTS.Common.Utilities.Logging;
namespace DTS.Serialization.TDM
{
public class ChannelHeader
{
internal const int MAX_HEADER_LINES = 15;
internal const int DAS_LINE = 0;
internal const int CAPACITY_LINE = 1;
internal const int EU_LINE = 2;
internal const int SENSOR_SN_LINE = 3;
internal const int SENSITIVITY_LINE = 4;
internal const int EXCITATION_LINE = 5;
internal const int MIN_LINE = 6;
internal const int MAX_LINE = 7;
internal const int TOYOTA_CALC1_LINE = 8;
internal const int TOYOTA_CALC2_LINE = 9;
internal const int TOYOTA_CALC3_LINE = 10;
internal const int KNEE_POINT_LINE = 11;
internal const int STRANGE_DATA_FLAG_LINE = 12;
internal const int CHANNEL_CODE_LINE = 13;
internal const int CHANNEL_JCODE_LINE = 14;
public void WriteChannelHeaderToString(Writer writer, System.IO.TextWriter tw, bool bFiltered, double start, double end)
{
var test = writer.Test;
writer.IncrementDone(2);
var HeaderLines = new string[MAX_HEADER_LINES];
for (var i = 0; i < MAX_HEADER_LINES; i++) { HeaderLines[i] = ""; }
var testChannels = new List<Test.Module.Channel>(test.Channels);
for (var i = 0; i < testChannels.Count; i++)
{
if (testChannels[i] is Test.Module.AnalogInputChannel)
{
var channel = testChannels[i] as Test.Module.AnalogInputChannel;
if (channel.IsSquibVoltage())
{
continue;
}
var startSampleNumber = start * channel.ParentModule.SampleRateHz + channel.ParentModule.TriggerSampleNumbers[0];
var endSampleNumber = end * channel.ParentModule.SampleRateHz + channel.ParentModule.TriggerSampleNumbers[0];
if (startSampleNumber < channel.ParentModule.StartRecordSampleNumber) { startSampleNumber = channel.ParentModule.StartRecordSampleNumber; }
if (endSampleNumber > channel.ParentModule.NumberOfSamples + (double)channel.ParentModule.StartRecordSampleNumber)
{
endSampleNumber = channel.ParentModule.StartRecordSampleNumber + (double)channel.ParentModule.NumberOfSamples;
}
var startSample = Convert.ToInt32(startSampleNumber - channel.ParentModule.StartRecordSampleNumber);
var endSample = Convert.ToInt32(endSampleNumber - channel.ParentModule.StartRecordSampleNumber - 1);
if (channel.IsDigital())
{
HeaderLines[DAS_LINE] = string.Format("{0},{1}", HeaderLines[DAS_LINE],
channel.HardwareChannelName);
HeaderLines[CAPACITY_LINE] = string.Format("{0},{1}", HeaderLines[CAPACITY_LINE], 1);
HeaderLines[EU_LINE] = string.Format("{0},{1}", HeaderLines[EU_LINE], "Digital");
HeaderLines[SENSOR_SN_LINE] = string.Format("{0},{1}", HeaderLines[SENSOR_SN_LINE], channel.HardwareChannelName);
}
else if (channel.IsSquib())
{
HeaderLines[DAS_LINE] = string.Format("{0},{1}", HeaderLines[DAS_LINE], channel.HardwareChannelName);
HeaderLines[CAPACITY_LINE] = string.Format("{0},{1}", HeaderLines[CAPACITY_LINE], 10); //hardcoded per TDM cpp file
HeaderLines[EU_LINE] = string.Format("{0},{1}", HeaderLines[EU_LINE], channel.EngineeringUnits.TrimEnd());
HeaderLines[SENSOR_SN_LINE] = string.Format("{0},{1}", HeaderLines[SENSOR_SN_LINE], channel.HardwareChannelName);
}
else
{
HeaderLines[DAS_LINE] = string.Format("{0},{1}", HeaderLines[DAS_LINE], channel.HardwareChannelName);
if (channel.ProportionalToExcitation || (channel.SensorCapacity == 0))
{
HeaderLines[CAPACITY_LINE] = string.Format("{0},{1}", HeaderLines[CAPACITY_LINE], channel.DesiredRange);
}
else
{
HeaderLines[CAPACITY_LINE] = string.Format("{0},{1}", HeaderLines[CAPACITY_LINE], channel.SensorCapacity);
}
HeaderLines[EU_LINE] = string.Format("{0},{1}", HeaderLines[EU_LINE], channel.EngineeringUnits.TrimEnd());
HeaderLines[SENSOR_SN_LINE] = string.Format("{0},{1}", HeaderLines[SENSOR_SN_LINE], channel.SerialNumber);
}
if (channel.IsSquib()) { HeaderLines[SENSITIVITY_LINE] = string.Format("{0},{1:0.000000000000}", HeaderLines[SENSITIVITY_LINE], 1D); }
else { HeaderLines[SENSITIVITY_LINE] = string.Format("{0},{1:0.000000000000}", HeaderLines[SENSITIVITY_LINE], channel.Sensitivity); }
if (channel.IsSquib())
{
HeaderLines[EXCITATION_LINE] = string.Format("{0},{1}", HeaderLines[EXCITATION_LINE], (5D).ToString("e4", CultureInfo.InvariantCulture));
}
else if (channel.IsDigital())
{
HeaderLines[EXCITATION_LINE] = string.Format("{0},{1}", HeaderLines[EXCITATION_LINE], (1D).ToString("e4", CultureInfo.InvariantCulture));
}
else
{
HeaderLines[EXCITATION_LINE] = string.Format("{0},{1}", HeaderLines[EXCITATION_LINE], channel.MeasuredExcitationVoltageValid ? channel.MeasuredExcitationVoltage.ToString("e4", CultureInfo.InvariantCulture)
: channel.FactoryExcitationVoltageValid ? channel.FactoryExcitationVoltage.ToString("e4", CultureInfo.InvariantCulture) : (5D).ToString("e4", CultureInfo.InvariantCulture));
}
var dMin = double.MaxValue;
var dMax = double.MinValue;
var scaler = new DataScaler();
scaler.IsInverted = channel.IsInverted;//channel is DTS.Common.DAS.Concepts.DAS.Channel.IInversionAware ? (channel as DTS.Common.DAS.Concepts.DAS.Channel.IInversionAware).IsInverted : false;
scaler.SetLinearizationFormula(channel.LinearizationFormula);
scaler.SetScaleFactorMv(channel.Data.ScaleFactorMv);
scaler.SetScaleFactorEU(channel.Data.ScaleFactorEU);
scaler.SetUseEUScaleFactors(channel.Data.UseEUScaleFactors);
scaler.UnitConversion = channel.UnitConversion;
scaler.BasedOnOutputAtCapacity = channel.AtCapacity;
scaler.CapacityOutputIsBasedOn = channel.CapacityOutputIsBasedOn;
scaler.SensitivityUnits = channel.SensitivityUnits;
scaler.IEPE = channel.Bridge == SensorConstants.BridgeType.IEPE;
scaler.Digital = channel.Bridge == SensorConstants.BridgeType.DigitalInput;
scaler.SetLinearizationFormula(channel.LinearizationFormula);
scaler.SetDigitalMultiplier(channel.DigitalMultiplier);
scaler.Digital = channel.IsDigital();
scaler.DigitalMode = channel.DigitalMode;
scaler.SetMvPerEu(channel.Data.MvPerEu);
var analogChannel = channel;
try
{
scaler.SetInitialOffset(analogChannel.InitialOffset);
scaler.ZeroMethodType = analogChannel.ZeroMethod;
if (analogChannel.RemoveOffset) { scaler.SetRemovedADC(channel.RemovedADC); scaler.SetRemovedInternalADC(channel.RemovedInternalADC); }
else { scaler.SetRemovedADC(0); scaler.SetRemovedInternalADC(0); }
scaler.SetDataZeroLevelADC(channel.DataZeroLevelAdc);
scaler.SetZeroMvInADC(channel.ZeroMvInADC);
try { scaler.SetWindowAverageADC(channel.WindowAverageADC); }
catch (Exception) { }
}
catch (Exception) { }
scaler.NominalExcitationVoltage = analogChannel.ExcitationVoltage;
if (analogChannel.MeasuredExcitationVoltageValid)
{
try { scaler.MeasuredExcitationVoltage = analogChannel.MeasuredExcitationVoltage; }
catch { };
}
if (analogChannel.FactoryExcitationVoltageValid)
{
try { scaler.FactoryExcitationVoltage = analogChannel.FactoryExcitationVoltage; }
catch { };
}
scaler.ProportionalToExcitation = channel.ProportionalToExcitation;
if (bFiltered)
{
for (var curSample = startSample; curSample <= endSample; curSample++)
{
var d = channel.Sensitivity * scaler.GetEU(writer.FilteredData[i].Data[Convert.ToUInt64(curSample)]);
dMin = Math.Min(dMin, d);
dMax = Math.Max(dMax, d);
}
}
else
{
for (var curSample = startSample; curSample <= endSample; curSample++)
{
try
{
var d = channel.Sensitivity * scaler.GetEU(channel.PersistentChannelInfo.Data[Convert.ToUInt64(curSample)]);
dMin = Math.Min(dMin, d);
dMax = Math.Max(dMax, d);
}
catch (IndexOutOfRangeException ex)
{
APILogger.Log("unexpected end in TDM export looking for min/max, ", ex);
break;
}
}
}
HeaderLines[MIN_LINE] = string.Format("{0},{1}", HeaderLines[MIN_LINE], dMin.ToString("e4", CultureInfo.InvariantCulture));
HeaderLines[MAX_LINE] = string.Format("{0},{1}", HeaderLines[MAX_LINE], dMax.ToString("e4", CultureInfo.InvariantCulture));
//11344 The function of Cable Multiplier on Analog Channels in TTS import is not ready yet
//var cableMultipler = "0"; //default in the old code
//if (!string.IsNullOrWhiteSpace(channel.UserValue2))
//{
// if (double.TryParse(channel.UserValue2, NumberStyles.Any, CultureInfo.InvariantCulture,
// out var dTemp))
// {
// cableMultipler = dTemp.ToString(CultureInfo.InvariantCulture);
// }
//}
//22284 Use a hardcoded value of 1 for cable multiplier for TTS export
HeaderLines[TOYOTA_CALC1_LINE] += $",1";
HeaderLines[TOYOTA_CALC2_LINE] += $",0";
HeaderLines[TOYOTA_CALC3_LINE] += ",0";
double softwareFrequency = 0;
if (channel.IsSquib())
{
softwareFrequency = 2000;
}
else
{
if (!string.IsNullOrEmpty(channel.SoftwareFilter))
{
if (channel.SoftwareFilter.Contains("Hz"))
{
double d;
if (double.TryParse(channel.SoftwareFilter.Replace("Hz", ""), out d))
{
softwareFrequency = d;
}
}
else
{
var coder = new DescriptionAttributeCoder<ChannelFilter>();
foreach (ChannelFilter filterType in Enum.GetValues(typeof(ChannelFilter)))
{
if (coder.DecodeAttributeValue(filterType).Equals(channel.SoftwareFilter, StringComparison.OrdinalIgnoreCase))
{
softwareFrequency = (double)filterType;
break;
}
}
}
}
}
// This used to have manipulation logic, but no more. See http://fogbugz/fogbugz/default.asp?4594
HeaderLines[KNEE_POINT_LINE] = string.Format("{0},{1}", HeaderLines[KNEE_POINT_LINE], softwareFrequency);
HeaderLines[STRANGE_DATA_FLAG_LINE] = string.Format("{0},{1}", HeaderLines[STRANGE_DATA_FLAG_LINE], channel.DataFlag);
//7714 Remove " (Current)" from AIC channel name/description in TTS export.
var chName = channel.UserCode;
if (channel.IsSquibChannel)
{
chName = channel.ChannelName2;
var index = chName.IndexOf(" (Current)");
if (index >= 0)
{
chName = chName.Substring(0, index);
}
}
HeaderLines[CHANNEL_CODE_LINE] = string.Format("{0},{1}", HeaderLines[CHANNEL_CODE_LINE], chName);
var description = channel.UserChannelName;
if (channel.IsSquib())
{
description = channel.ChannelDescriptionString;
var index = description.IndexOf(" (Current)");
if (index >= 0) { description = description.Remove(index, 10); }
}
HeaderLines[CHANNEL_JCODE_LINE] = string.Format("{0},{1}", HeaderLines[CHANNEL_JCODE_LINE], description);
}
}
foreach (var line in HeaderLines)
{
tw.WriteLine("{0},", line);
}
}
}
}

View File

@@ -0,0 +1,56 @@
namespace DTS.Serialization.TDM
{
public class File : Serialization.File, IWritable<Test>
{
public File()
: base("TDM CFC1000")
{
}
/*/// <summary>
/// Get this file format's extension.
/// </summary>
static public string Extension
{
get { return ".tlf"; }
}*/
/// <summary>
/// Get the file writer for this file type.
/// </summary>
public IWriter<Test> Exporter
{
get
{
try
{
if (_Exporter == null)
_Exporter = new Writer(this, DefaultEncoding);
(_Exporter as Writer).Start = Start;
(_Exporter as Writer).Stop = Stop;
return _Exporter;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting exporter", ex);
}
}
}
private IWriter<Test> _Exporter = null;
private double _start = 0D;
public double Start
{
get => _start;
set => _start = value;
}
private double _stop = 0D;
public double Stop
{
get => _stop;
set => _stop = value;
}
}
}

View File

@@ -0,0 +1,256 @@
namespace DTS.Serialization.TDM
{
partial class TDMParameterDlg
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.tblLayout = new System.Windows.Forms.TableLayoutPanel();
this.label1 = new System.Windows.Forms.Label();
this.btnBrowse = new System.Windows.Forms.Button();
this.tbLocation = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.tbStart = new System.Windows.Forms.TextBox();
this.tbStop = new System.Windows.Forms.TextBox();
this.label4 = new System.Windows.Forms.Label();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.btnOK = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.label5 = new System.Windows.Forms.Label();
this.label6 = new System.Windows.Forms.Label();
this.errorProvider1 = new System.Windows.Forms.ErrorProvider(this.components);
this.tblLayout.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.errorProvider1)).BeginInit();
this.SuspendLayout();
//
// tblLayout
//
this.tblLayout.ColumnCount = 4;
this.tblLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tblLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tblLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tblLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tblLayout.Controls.Add(this.label1, 0, 0);
this.tblLayout.Controls.Add(this.btnBrowse, 3, 0);
this.tblLayout.Controls.Add(this.tbLocation, 1, 0);
this.tblLayout.Controls.Add(this.label2, 0, 2);
this.tblLayout.Controls.Add(this.label3, 0, 1);
this.tblLayout.Controls.Add(this.tbStart, 1, 2);
this.tblLayout.Controls.Add(this.tbStop, 1, 3);
this.tblLayout.Controls.Add(this.label4, 0, 3);
this.tblLayout.Controls.Add(this.tableLayoutPanel1, 0, 4);
this.tblLayout.Controls.Add(this.label5, 2, 2);
this.tblLayout.Controls.Add(this.label6, 2, 3);
this.tblLayout.Dock = System.Windows.Forms.DockStyle.Fill;
this.tblLayout.Location = new System.Drawing.Point(0, 0);
this.tblLayout.Name = "tblLayout";
this.tblLayout.RowCount = 5;
this.tblLayout.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tblLayout.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tblLayout.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tblLayout.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tblLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tblLayout.Size = new System.Drawing.Size(511, 136);
this.tblLayout.TabIndex = 0;
//
// label1
//
this.label1.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(3, 8);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(48, 13);
this.label1.TabIndex = 0;
this.label1.Text = "Location";
//
// btnBrowse
//
this.btnBrowse.Location = new System.Drawing.Point(433, 3);
this.btnBrowse.Name = "btnBrowse";
this.btnBrowse.Size = new System.Drawing.Size(75, 23);
this.btnBrowse.TabIndex = 1;
this.btnBrowse.Text = "Browse";
this.btnBrowse.UseVisualStyleBackColor = true;
this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
//
// tbLocation
//
this.tbLocation.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.tblLayout.SetColumnSpan(this.tbLocation, 2);
this.tbLocation.Location = new System.Drawing.Point(57, 4);
this.tbLocation.Name = "tbLocation";
this.tbLocation.Size = new System.Drawing.Size(370, 20);
this.tbLocation.TabIndex = 2;
//
// label2
//
this.label2.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(3, 48);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(29, 13);
this.label2.TabIndex = 3;
this.label2.Text = "Start";
//
// label3
//
this.label3.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label3.AutoSize = true;
this.tblLayout.SetColumnSpan(this.label3, 2);
this.label3.Location = new System.Drawing.Point(3, 29);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(158, 13);
this.label3.TabIndex = 4;
this.label3.Text = "Start and Stop are relative to T0";
//
// tbStart
//
this.tbStart.Location = new System.Drawing.Point(57, 45);
this.tbStart.Name = "tbStart";
this.tbStart.Size = new System.Drawing.Size(100, 20);
this.tbStart.TabIndex = 5;
this.tbStart.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
//
// tbStop
//
this.tbStop.Location = new System.Drawing.Point(57, 71);
this.tbStop.Name = "tbStop";
this.tbStop.Size = new System.Drawing.Size(100, 20);
this.tbStop.TabIndex = 6;
this.tbStop.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
//
// label4
//
this.label4.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(3, 74);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(29, 13);
this.label4.TabIndex = 7;
this.label4.Text = "Stop";
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.tableLayoutPanel1.ColumnCount = 2;
this.tblLayout.SetColumnSpan(this.tableLayoutPanel1, 4);
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.Controls.Add(this.btnOK, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.btnCancel, 1, 0);
this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 97);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 1;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(505, 36);
this.tableLayoutPanel1.TabIndex = 8;
//
// btnOK
//
this.btnOK.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.btnOK.Location = new System.Drawing.Point(174, 6);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(75, 23);
this.btnOK.TabIndex = 0;
this.btnOK.Text = "&OK";
this.btnOK.UseVisualStyleBackColor = true;
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
//
// btnCancel
//
this.btnCancel.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.btnCancel.Location = new System.Drawing.Point(255, 6);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 1;
this.btnCancel.Text = "&Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// label5
//
this.label5.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(167, 48);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(26, 13);
this.label5.TabIndex = 9;
this.label5.Text = "(ms)";
//
// label6
//
this.label6.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(167, 74);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(26, 13);
this.label6.TabIndex = 10;
this.label6.Text = "(ms)";
//
// errorProvider1
//
this.errorProvider1.ContainerControl = this;
//
// TDMParameterDlg
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(239)))), ((int)(((byte)(246)))), ((int)(((byte)(253)))));
this.ClientSize = new System.Drawing.Size(511, 136);
this.Controls.Add(this.tblLayout);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
this.Name = "TDMParameterDlg";
this.Text = "TDM Export Parameters";
this.tblLayout.ResumeLayout(false);
this.tblLayout.PerformLayout();
this.tableLayoutPanel1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.errorProvider1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TableLayoutPanel tblLayout;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button btnBrowse;
private System.Windows.Forms.TextBox tbLocation;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox tbStart;
private System.Windows.Forms.TextBox tbStop;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Button btnOK;
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.ErrorProvider errorProvider1;
}
}

View File

@@ -0,0 +1,105 @@
using System;
using System.Windows.Forms;
namespace DTS.Serialization.TDM
{
public partial class TDMParameterDlg : Form
{
private readonly double _min;
private readonly double _max;
protected TDMParameterDlg()
{
}
public TDMParameterDlg(string testName, double testStart, double testEnd)
{
InitializeComponent();
DialogResult = DialogResult.Cancel;
var di = new System.IO.DirectoryInfo(Properties.Settings1.Default.TDMFolder);
if (!di.Exists)
{
di.Create();
}
var path = System.IO.Path.Combine(di.FullName, string.Format("{0}.csv", testName));
tbLocation.Text = path;
//tbStart.Text = (testStart*1000D).ToString();
//tbStop.Text = (testEnd*1000D).ToString();
var start = testStart * 1000D;
var stop = testEnd * 1000D;
_min = start;
_max = stop;
if (Properties.Settings1.Default.DefaultStart < start) { tbStart.Text = start.ToString(); }
else { tbStart.Text = Properties.Settings1.Default.DefaultStart.ToString(); }
if (Properties.Settings1.Default.DefaultStop > stop) { tbStop.Text = stop.ToString(); }
else { tbStop.Text = Properties.Settings1.Default.DefaultStop.ToString(); }
}
private void btnBrowse_Click(object sender, EventArgs e)
{
using (var dlg = new SaveFileDialog())
{
dlg.Filter = "TDM CSV (*.csv)|*.csv";
dlg.FilterIndex = 0;
dlg.RestoreDirectory = true;
dlg.OverwritePrompt = true;
var fi = new System.IO.FileInfo(tbLocation.Text);
dlg.InitialDirectory = fi.Directory.FullName;
dlg.FileName = tbLocation.Text;
if (DialogResult.OK == dlg.ShowDialog(this))
{
tbLocation.Text = dlg.FileName;
}
}
}
private void btnOK_Click(object sender, EventArgs e)
{
errorProvider1.SetError(tbStart, null);
errorProvider1.SetError(tbStop, null);
var fi = new System.IO.FileInfo(tbLocation.Text);
Properties.Settings1.Default.TDMFolder = fi.Directory.FullName;
var dstart = double.MinValue;
if (double.TryParse(tbStart.Text, out dstart))
{
Properties.Settings1.Default.DefaultStart = dstart;
}
else
{
errorProvider1.SetError(tbStart, "Could not parse");
return;
}
var dend = double.MinValue;
if (double.TryParse(tbStop.Text, out dend))
{
Properties.Settings1.Default.DefaultStop = dend;
}
else
{
errorProvider1.SetError(tbStop, "Could not parse");
return;
}
if (dend < dstart) { errorProvider1.SetError(tbStart, "Start must be before end"); return; }
if (dend > _max) { errorProvider1.SetError(tbStop, string.Format("exceeds max data in test ({0} ms)", _max)); return; }
if (dstart < _min) { errorProvider1.SetError(tbStart, string.Format("test does not contain requested region, min start is ({0} ms)", _min)); return; }
Properties.Settings1.Default.Save();
DialogResult = DialogResult.OK;
Close();
}
public string FileName => tbLocation.Text;
public double Start => double.Parse(tbStart.Text) / 1000D;
public double Stop => double.Parse(tbStop.Text) / 1000D;
private void btnCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
}
}

View File

@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="errorProvider1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View File

@@ -0,0 +1,200 @@
using System;
using System.Linq;
namespace DTS.Serialization.TDM
{
public class TestHeader
{
internal const int MAX_TESTDEVICES = 1000;
internal const int MAX_DUMMY_DISPLAY = 16;
internal const int MAX_BARRIER_DISPLAY = 3;
internal const int MAX_GROUP_DISPLAY = 20;
internal const int MAX_DEVICE_DISPLAY = MAX_DUMMY_DISPLAY + MAX_BARRIER_DISPLAY + MAX_GROUP_DISPLAY + 1;
internal const char DEV_TYPE_DUMMY = 'D';
internal const char DEV_TYPE_BARRIER = 'B';
internal const char DEV_TYPE_GROUP = 'G';
internal const char DEV_TYPE_UNDEFINED = 'U';
internal const int MAX_DEVICE_LINES = 23;
internal const int MAX_OLD_GROUP_LINES = 4;
public void WriteTestHeader(Writer writer, System.IO.TextWriter tw, bool bFiltered, UInt16 subSampleInterval, ulong numSamples, int preTriggerSamples)
{
var test = writer.Test;
writer.IncrementDone(1);
tw.WriteLine("{0},", test.Id);//test id
tw.WriteLine("{0},", 0);//impact speed 1
tw.WriteLine("{0},", 0);//impact weight 1
tw.WriteLine("{0},", 0);//impact speed 2
tw.WriteLine("{0},", 0);//impact weight 2
tw.WriteLine("{0},", "km/h");//unit (m/s or km/h)
//test start date
tw.WriteLine("'{0:00}-{1:00}-{2:00},", test.InceptionDate.Year - 2000, test.InceptionDate.Month, test.InceptionDate.Day);
//test start time
tw.WriteLine("{0:00}:{1:00}:{2:00},", test.InceptionDate.Hour, test.InceptionDate.Minute, test.InceptionDate.Second);
var testCompleteTime = (test.InceptionDate.AddSeconds(test.Modules[0].PreTriggerSeconds).AddSeconds(test.Modules[0].PostTriggerSeconds));
//test complete time
tw.WriteLine("{0:00}:{1:00}:{2:00},", testCompleteTime.Hour, testCompleteTime.Minute, testCompleteTime.Second);
// Note this section is not completely implemented equivalent to TDM. Specifically, the dummy list passed in
// the test description works, but the notion of barriers and groups and written with blank lines. TBD if THF or TEMA really need this and
// how we would propigate that information.
var userValue3 = test.Channels.FirstOrDefault().UserValue3;
string[] dummyList;
if (!string.IsNullOrEmpty(userValue3))
{
dummyList = test.Channels.FirstOrDefault().UserValue3.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
}
else
{
dummyList = new string[0];
}
var barrierCount = 0;
var groupCount = 0;
var dummyCount = dummyList.Count();
// this is only of importance if we have more than 4 groups
// and if the others are full we're stuck
if (groupCount > MAX_OLD_GROUP_LINES && !(dummyCount == MAX_DUMMY_DISPLAY && barrierCount == MAX_BARRIER_DISPLAY))
{
// we must prioritize dummies and barriers
if (MAX_DEVICE_LINES - dummyCount - barrierCount >= groupCount)
{
// this will be a full house
groupCount = MAX_DEVICE_LINES - dummyCount - barrierCount;
WriteDeviceSection(test, DEV_TYPE_DUMMY, dummyCount, dummyCount, tw, dummyList);
WriteDeviceSection(test, DEV_TYPE_BARRIER, barrierCount, barrierCount, tw, null);
WriteDeviceSection(test, DEV_TYPE_GROUP, groupCount, groupCount, tw, null);
}
else
{
// the only thing we know now is that groupCount > MAX_OLD_GROUP_LINES
if (dummyCount == 0)
{
if (barrierCount == 0)
{
// we only have groups, easy
WriteDeviceSection(test, DEV_TYPE_GROUP, MAX_DEVICE_LINES, groupCount, tw, null);
}
else
{
// we have barriers and groups
var spaceAvail = MAX_DEVICE_LINES - barrierCount - groupCount;
WriteDeviceSection(test, DEV_TYPE_BARRIER, barrierCount + spaceAvail, barrierCount, tw, null);
WriteDeviceSection(test, DEV_TYPE_GROUP, groupCount, groupCount, tw, null);
}
}
else
{
if (barrierCount == 0)
{
// we have dummies and groups
var spaceAvail = MAX_DEVICE_LINES - dummyCount - groupCount;
WriteDeviceSection(test, DEV_TYPE_DUMMY, dummyCount + spaceAvail, dummyCount, tw, null);
WriteDeviceSection(test, DEV_TYPE_GROUP, groupCount, groupCount, tw, null);
}
else
{
// we have all three types
var spaceAvail = MAX_DEVICE_LINES - dummyCount - barrierCount - groupCount;
var firstSpace = spaceAvail / 2;
WriteDeviceSection(test, DEV_TYPE_DUMMY, dummyCount + firstSpace, dummyCount, tw, dummyList);
WriteDeviceSection(test, DEV_TYPE_BARRIER, barrierCount + spaceAvail - firstSpace, barrierCount, tw, null);
WriteDeviceSection(test, DEV_TYPE_GROUP, groupCount, groupCount, tw, null);
}
}
}
}
else
{
// this is the normal case with less than 5 groups
WriteDeviceSection(test, DEV_TYPE_DUMMY, MAX_DUMMY_DISPLAY, MAX_DUMMY_DISPLAY, tw, dummyList);
WriteDeviceSection(test, DEV_TYPE_BARRIER, MAX_BARRIER_DISPLAY, MAX_BARRIER_DISPLAY, tw, null);
WriteDeviceSection(test, DEV_TYPE_GROUP, MAX_OLD_GROUP_LINES, MAX_OLD_GROUP_LINES, tw, null);
}
var TotalSamples = ulong.MaxValue;
//the lowest common start in samples from t0 that all modules have
var minStart = double.MinValue;
//the highest common end in samples from t0 that all modules have
var maxEnd = double.MaxValue;
foreach (var module in test.Modules)
{
//Don't process Slice6DB modules that were created to store Temperature values from Arm checklist
if (module.Channels.Count <= 0) continue;
//TriggerSampleNumber = Math.Min(TriggerSampleNumber, module.TriggerSampleNumbers[0]);
TotalSamples = Math.Min(TotalSamples, module.NumberOfSamples);
//System.Diagnostics.Trace.Assert(module.TriggerSampleNumbers[0] >= module.StartRecordSampleNumber);
double mStart = module.TriggerSampleNumbers[0] - module.StartRecordSampleNumber;
minStart = Math.Max(minStart, mStart);
var mEnd = module.NumberOfSamples - mStart;
maxEnd = Math.Min(maxEnd, mEnd);
}
if (preTriggerSamples < 0)
{
preTriggerSamples = 0;
}
else if (preTriggerSamples > (int)numSamples)
{
//All of the ROI is pre-trigger
preTriggerSamples = (int)numSamples;
}
tw.WriteLine("{0},", preTriggerSamples);
tw.WriteLine("{0},", (int)numSamples - preTriggerSamples);
tw.WriteLine("{0},", numSamples);
tw.WriteLine("{0},", subSampleInterval);
tw.WriteLine("{0},", Math.Truncate(test.Modules[0].SampleRateHz / subSampleInterval));
var tomVoltageCount = 0;
foreach (var currentChannel in test.Channels)
{
if (currentChannel is Test.Module.AnalogInputChannel analogChannel && analogChannel.IsSquibVoltage())
{
tomVoltageCount++;
}
}
tw.WriteLine("{0},", test.Channels.Count - tomVoltageCount);
tw.WriteLine("{0},", test.Description);
}
private void WriteDeviceSection(Test test, char devType, int totalSize, int maxDevices, System.IO.TextWriter tw, string[] DeviceList)
{
var DeviceCount = 0;
var channelCount = test.Channels.Count;
for (var Index = 0; Index < MAX_DEVICE_DISPLAY && Index < channelCount; Index++)
{
if (devType == DEV_TYPE_DUMMY)//if (TestPtr->DeviceList[Index].DeviceType == devType)
{
if (Index < DeviceList.Count() && !String.IsNullOrEmpty(DeviceList[Index]))
{
tw.Write(DeviceList[Index]);
}
tw.WriteLine(",");
DeviceCount++;
}
// make sure we don't do more than
if (DeviceCount == maxDevices)
{
break;
}
}
// pad until MAX_DUMMY_DISPLAY lines
for (/*NOOP*/; DeviceCount < totalSize; DeviceCount++)
{
tw.WriteLine(",");
//fprintf(fp, ",\n");
}
}
}
}

View File

@@ -0,0 +1,219 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DTS.Common.DAS.Concepts;
using DTS.Common.Utilities.Logging;
namespace DTS.Serialization.TDM
{
public class Writer : Serialization.File.Writer<File>, IWriter<Test>
{
public bool AllowTTSExportFiltering { get; set; } = false;
public double Start { get; set; }
public double Stop { get; set; }
public List<FilteredData> FilteredData { get; set; }
public Test Test { get; set; }
public ulong IncrementLevel { get; private set; }
public ushort SubSampleInterval { get; set; }
public string ExtensionPrefix { get; set; } = string.Empty;
internal Writer(File fileType, int encoding)
: base(fileType, encoding)
{
}
///
/// <summary>
/// Generate the path-specified serialization from the given object.
/// </summary>
///
/// <param name="pathname">
/// The <see cref="string"/> pathname to which the serialization will be written.
/// </param>
///
/// <param name="target">
/// The object to be serialized.
/// </param>
///
public void Write(string pathname, string id, Test target, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)
{
throw new NotSupportedException("TDM::Writer Write(pathname, id, test, bFiltering) not supported");
}
/// <summary>
/// Generate the path-specified serialization from the given object.
/// </summary>
///
/// <param name="pathname">
/// The <see cref="string"/> pathname to which the serialization will be written.
/// </param>
///
/// <param name="target">
/// The object to be serialized.
/// </param>
///
/// <param name="onBeginEvent">
/// The <see cref="DTS.Serialization.BeginEventHandler"/> to be notified when the write begins.
/// </param>
///
/// <param name="onEndEvent">
/// The <see cref="DTS.Serialization.EndEventHandler"/> to be notified when the write completes.
/// </param>
///
/// <param name="onTickEvent">
/// The <see cref="DTS.Serialization.TickEventHandler"/> to be notified when the write "progresses".
/// </param>
///
public void Write(string pathname,
string id,
string dataFolder,
Test target,
bool bFiltering,
bool includeGroupNameInISOExport,
FilteredData fd,
Test.Module.Channel tmChannel,
int channelNumber,
BeginEventHandler onBeginEvent,
CancelEventHandler onCancelEvent,
EndEventHandler onEndEvent,
TickEventHandler onTickEvent,
ErrorEventHandler onErrorEvent,
CancelRequested cancelRequested,
double minStartTime,
int dataCollectionLength)
{
Test = target;
try
{
_onTickEvent = onTickEvent;
//There are some cases in Data Pro where the UI is storing precision that is not communicated to the user. For example, an ROI of 0.500 seconds
// may actually be represented as 0.5001. There is nothing magic about it - standard floating point problem. However the roots
// of it are actually in differences between the download code of TDAS and SLICE. SLICE doesn't care about trigger sample numbers, but
// TDAS download is expressed as sample around t=0 with t=0 sample implied. This too is not really a big deal. Where it gets ugly is in reconciling
// the fact that Data PRO, SLICEWare, and the services are written around the SLICE model.
// For now (and this is definitely a hack), round to the nearest millisecond. This should be transparent if/when the root problem is fixed.
Start = Math.Round(Start, 3);
Stop = Math.Round(Stop, 3);
var maxRate = Test.Channels.Select(ch => ch.ParentModule.SampleRateHz).Max();
var numSamples = (Stop - Start) * maxRate;
//the way the dataform handles ticks is a little weird, it expects an uint below and can only handle single tick
//progress updates, despite saying "percentage", so this is just a safety check for the case of large number of samples
//it's probably won't be needed.
if (numSamples * 2D / 100 > int.MaxValue) { IncrementLevel = 10000; }
else if (numSamples < 10000) { IncrementLevel = 10; }//also probably unlikely, but in the case of
//a huge number of channels and not many samples, it'd be nice to see something
else { IncrementLevel = 1000; }
var ticksNeeded = 4D + 2D * numSamples / IncrementLevel;
onBeginEvent?.Invoke(this, Convert.ToUInt32(ticksNeeded));
DoExport(false, pathname, Start, Stop, AllowTTSExportFiltering);
}
catch (System.Exception ex) { throw ex; }
finally
{
onTickEvent?.Invoke(this, 100D);
onEndEvent?.Invoke(this);
}
}
public void Initialize(string pathname,
string id,
string dataFolder,
Test test,
bool bFiltering,
bool includeGroupNameInISOExport,
FilteredData fd,
Test.Module.Channel tmChannel,
int channelNumber,
BeginEventHandler beginEventHandler,
CancelEventHandler cancelEventHandler,
EndEventHandler endEventHandler,
TickEventHandler tickEventHandler,
ErrorEventHandler errorEventHandler,
CancelRequested cancelRequested)
{
}
private TickEventHandler _onTickEvent;
public void IncrementDone(double amount)
{
_onTickEvent(this, amount);
}
private void DoExport(bool bFiltered, string pathname, double start, double stop, bool allowTTSFilteredExport)
{
var format = "{0}{1}.csv";
var fileName = System.IO.Path.Combine(pathname, Test.Id);
if (1 != SubSampleInterval)
{
fileName += "_Subsampled";
}
fileName = string.Format(format, fileName, ExtensionPrefix ?? "");
System.IO.TextWriter tw = null;
try
{
Encoding encoder = new UTF8Encoding(true);
try
{
if (DefaultEncoding != Encoding.UTF8.CodePage)
{
encoder = Common.Utils.FileUtils.GetEncoding(DefaultEncoding);
}
}
catch (System.Exception ex)
{
APILogger.Log("Problem getting encoding", ex);
encoder = Encoding.Default;
}
tw = new System.IO.StreamWriter(fileName, false, encoder);
var th = new TestHeader();
var ch = new ChannelHeader();
var cd = new ChannelData();
var bFilterThisExport = bFiltered && allowTTSFilteredExport;
cd.GenerateChannelData(this, tw, bFilterThisExport, start, stop, SubSampleInterval, out ulong practicalNumSamples, out ulong numSamples, out Test test, out DataScaler[] scalers, out double sampleRate,
out List<short[]> ChannelDataUnFiltered, out List<double[]> ChannelDataFiltered, out int preTriggerSamples);
th.WriteTestHeader(this, tw, bFilterThisExport, SubSampleInterval, Math.Min(numSamples, practicalNumSamples), preTriggerSamples);
ch.WriteChannelHeaderToString(this, tw, bFilterThisExport, start, stop);
cd.WriteChannelData(this, tw, bFilterThisExport, start, stop, SubSampleInterval, practicalNumSamples, numSamples, test, scalers, sampleRate, ChannelDataUnFiltered,
ChannelDataFiltered);
}
catch (System.Exception ex)
{
APILogger.Log("Exception in DoExport, ", ex);
throw ex;
}
finally
{
if (null != tw)
{
try
{
tw.Flush();
tw.Close();
tw.Dispose();
}
catch (System.Exception ex)
{
APILogger.Log("Exception in DoExport cleanup, ", ex);
}
tw = null;
}
}
}
}
}