220 lines
9.3 KiB
C#
220 lines
9.3 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|