init
This commit is contained in:
321
Common/DTS.Common.Serialization/TDM/ChannelData.cs
Normal file
321
Common/DTS.Common.Serialization/TDM/ChannelData.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
273
Common/DTS.Common.Serialization/TDM/ChannelHeader.cs
Normal file
273
Common/DTS.Common.Serialization/TDM/ChannelHeader.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Common/DTS.Common.Serialization/TDM/File.cs
Normal file
56
Common/DTS.Common.Serialization/TDM/File.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
256
Common/DTS.Common.Serialization/TDM/TDMParameterDlg.Designer.cs
generated
Normal file
256
Common/DTS.Common.Serialization/TDM/TDMParameterDlg.Designer.cs
generated
Normal 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;
|
||||
}
|
||||
}
|
||||
105
Common/DTS.Common.Serialization/TDM/TDMParameterDlg.cs
Normal file
105
Common/DTS.Common.Serialization/TDM/TDMParameterDlg.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
123
Common/DTS.Common.Serialization/TDM/TDMParameterDlg.resx
Normal file
123
Common/DTS.Common.Serialization/TDM/TDMParameterDlg.resx
Normal 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>
|
||||
200
Common/DTS.Common.Serialization/TDM/TestHeader.cs
Normal file
200
Common/DTS.Common.Serialization/TDM/TestHeader.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
219
Common/DTS.Common.Serialization/TDM/Writer.cs
Normal file
219
Common/DTS.Common.Serialization/TDM/Writer.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user