614 lines
29 KiB
C#
614 lines
29 KiB
C#
/*
|
|
* Chapter10.File.Writer.cs
|
|
*
|
|
* Copyright © 2020
|
|
* Diversified Technical Systems, Inc.
|
|
* All Rights Reserved
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing.Text;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using DTS.Common;
|
|
using DTS.Common.DAS.Concepts;
|
|
using DTS.Common.Enums;
|
|
using DTS.Common.Utilities.Logging;
|
|
using DTS.Common.Utils;
|
|
using static DTS.Serialization.Test.Module;
|
|
// ReSharper disable PossiblyMistakenUseOfParamsMethod
|
|
|
|
namespace DTS.Serialization.IRIGCH10
|
|
{
|
|
public partial class File
|
|
{
|
|
/// <summary>
|
|
/// implementation of the Serialization.File.Writer class for Chapter10
|
|
/// </summary>
|
|
public class Writer : Writer<File>, IWriter<Test>
|
|
{
|
|
#region properties
|
|
/// <summary>
|
|
/// the owning file that controls this writer
|
|
/// </summary>
|
|
internal File WriterParent { get; }
|
|
|
|
public double Start { get; set; }
|
|
public double Stop { get; set; }
|
|
public bool Filtered { get; set; }
|
|
|
|
#endregion
|
|
|
|
#region methods
|
|
/// <summary>
|
|
/// writes out test to given path
|
|
/// </summary>
|
|
/// <param name="pathname"></param>
|
|
/// <param name="id"></param>
|
|
/// <param name="test"></param>
|
|
/// <param name="bFiltering"></param>
|
|
/// <param name="includeGroupNameInISOExport"></param>
|
|
/// <param name="dataCollectionLength"></param>
|
|
/// <param name="minStartTime"></param>
|
|
public void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// updates the progress if possible
|
|
/// </summary>
|
|
/// <param name="dValue"></param>
|
|
/// <param name="tickEventHandler"></param>
|
|
private void UpdateProgress(double dValue, TickEventHandler tickEventHandler)
|
|
{
|
|
tickEventHandler?.Invoke(this, dValue);
|
|
}
|
|
/// <summary>
|
|
/// returns a name for the given channel
|
|
/// </summary>
|
|
/// <param name="channel"></param>
|
|
/// <returns></returns>
|
|
private static string GetChannelName(Channel channel)
|
|
{
|
|
|
|
if (!(channel is AnalogInputChannel aic))
|
|
{
|
|
return channel.ChannelName2;
|
|
}
|
|
|
|
switch (IsoViewModeStatic.ViewMode)
|
|
{
|
|
case IsoViewMode.ISOOnly:
|
|
return $"{aic.IsoChannelName}";
|
|
case IsoViewMode.ISOAndUserCode:
|
|
return $"{aic.IsoChannelName}\\{aic.UserChannelName}";
|
|
case IsoViewMode.UserCodeOnly:
|
|
return $"{aic.UserCode}";
|
|
case IsoViewMode.ChannelNameOnly:
|
|
return $"{aic.UserChannelName}";
|
|
}
|
|
return aic.HardwareChannelName;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// we don't really have an RTC, so we make up one
|
|
/// with an arbitrary value, this is actually a 6byte value,
|
|
/// we're just using a long for convenience
|
|
/// </summary>
|
|
public const long BASE_RTC = 141989612500056L;
|
|
private void GetTimeStamp(Test test, out int nanoseconds, out int seconds)
|
|
{
|
|
nanoseconds = 0;
|
|
seconds = 0;
|
|
var basemodules = test.Modules.GroupBy(module => module.BaseSerialNumber).Select(group => group.First());
|
|
|
|
var testModuleTimeStamps = GetModuleTimeStamps(basemodules, out var testModuleStartTimestamps);
|
|
|
|
Tuple<double, double> minUnixTime = null;
|
|
|
|
if (testModuleTimeStamps.Any())
|
|
{
|
|
minUnixTime = TestUtils.MinUnixTime(testModuleTimeStamps);
|
|
}
|
|
else if (testModuleStartTimestamps.Any())
|
|
{
|
|
minUnixTime = TestUtils.MinUnixTime(testModuleStartTimestamps);
|
|
}
|
|
|
|
if (null == minUnixTime)
|
|
{
|
|
var ticks = test.InceptionDate.ToUniversalTime().Ticks;
|
|
var s = Math.Truncate((decimal)ticks / TimeSpan.TicksPerSecond);
|
|
ticks -= Convert.ToInt64(s * TimeSpan.TicksPerSecond);
|
|
var n = Math.Truncate(ticks * Common.Constants.NANOS_PER_SECOND / TimeSpan.TicksPerSecond);
|
|
minUnixTime = new Tuple<double, double>(Convert.ToDouble(n), Convert.ToDouble(s));
|
|
}
|
|
|
|
var minStartTime = double.MinValue;
|
|
foreach (var module in test.Modules)
|
|
{
|
|
var dStartTime = (double)module.StartRecordSampleNumber / module.SampleRateHz;
|
|
if (module.TriggerSampleNumbers.Count > 0)
|
|
{
|
|
dStartTime -= (double)module.TriggerSampleNumbers[0] / module.SampleRateHz;
|
|
}
|
|
minStartTime = Math.Max(minStartTime, dStartTime);
|
|
}
|
|
var nanos = ((decimal)(minStartTime) * Common.Constants.NANOS_PER_SECOND) + (decimal)minUnixTime.Item2 + (decimal)minUnixTime.Item1 * Common.Constants.NANOS_PER_SECOND;
|
|
seconds = Convert.ToInt32(Math.Truncate(nanos / Common.Constants.NANOS_PER_SECOND));
|
|
nanos -= seconds * Common.Constants.NANOS_PER_SECOND;
|
|
nanoseconds = Convert.ToInt32(nanos);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// whether to include secondary time header or not
|
|
/// 33199 Add Time format 1 as an export option for CH 10 export
|
|
/// </summary>
|
|
public bool IncludeSecondaryHeader { get; set; } = true;
|
|
/// <summary>
|
|
/// Whether to use analog format or not during export
|
|
/// </summary>
|
|
public bool UseAnalogFormat { get; set; } = true;
|
|
/// <summary>
|
|
/// Whether to use PCM format or not during export
|
|
/// </summary>
|
|
public bool UsePCMFormat { get; set; } = false;
|
|
/// <summary>
|
|
/// returns a list of binary readers given a test that all point at the start of data
|
|
/// </summary>
|
|
/// <param name="test"></param>
|
|
/// <returns></returns>
|
|
private List<BinaryReader> GetBinaryReaders(Test test, IReadOnlyDictionary<Channel, ChannelInformation> lookup)
|
|
{
|
|
var binaryReaders = new List<BinaryReader>();
|
|
for (var i = 0; i < test.Channels.Count; i++)
|
|
{
|
|
var channel = test.Channels[i];
|
|
//get the filename and the start of data before we go and nuke the persistantchannelinfo object ...
|
|
var fileName = lookup[channel].ChannelFileName;
|
|
var offset = lookup[channel].OffsetDataStart;
|
|
//get the reader and advance it to the start of data
|
|
var br = new BinaryReader(new FileStream(fileName, FileMode.Open));
|
|
br.ReadBytes(Convert.ToInt32(offset));
|
|
lookup[channel].Reader = br;
|
|
binaryReaders.Add(br);
|
|
}
|
|
return binaryReaders;
|
|
}
|
|
/// <summary>
|
|
/// internal class for encapsulating some of the information from analoginputdaschannels without keeping any files open
|
|
/// </summary>
|
|
internal class ChannelInformation
|
|
{
|
|
public string ChannelFileName;
|
|
public ulong OffsetDataStart;
|
|
public ulong NumberOfSamples;
|
|
public short MinADC { get; set; } = short.MaxValue;
|
|
public short MaxADC { get; set; } = short.MinValue;
|
|
public BinaryReader Reader;
|
|
public ChannelInformation(AnalogInputChannel channel)
|
|
{
|
|
ChannelFileName = channel.PersistentChannelInfo.Filename;
|
|
OffsetDataStart = channel.PersistentChannelInfo.OffsetOfSampleDataStart;
|
|
NumberOfSamples = channel.PersistentChannelInfo.NumberOfSamples;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// retrieves channel summary information for channels in a test
|
|
/// </summary>
|
|
/// <param name="test"></param>
|
|
/// <returns></returns>
|
|
private IReadOnlyDictionary<Channel, ChannelInformation> GetChannelSummaries(Test test)
|
|
{
|
|
var lookup = new Dictionary<Channel, ChannelInformation>();
|
|
|
|
foreach (var channel in test.Channels)
|
|
{
|
|
if (channel is AnalogInputChannel aic)
|
|
{
|
|
lookup[channel] = new ChannelInformation(aic);
|
|
}
|
|
}
|
|
|
|
return lookup;
|
|
}
|
|
/// <summary>
|
|
/// closes and disposes of all readers in list, then clears the list
|
|
/// </summary>
|
|
/// <param name="readers"></param>
|
|
private void CloseAndDisposeReaders(List<BinaryReader> readers)
|
|
{
|
|
for (var i = 0; i < readers.Count; i++)
|
|
{
|
|
readers[i].Close();
|
|
readers[i].Dispose();
|
|
}
|
|
readers.Clear();
|
|
}
|
|
/// <summary>
|
|
/// go throughs all binary readers and determines the min and max ADC from files
|
|
/// </summary>
|
|
/// <param name="test"></param>
|
|
/// <param name="lookup"></param>
|
|
/// <param name="tickEventHandler"></param>
|
|
private void GetMinAndMax(Test test, IReadOnlyDictionary<Channel, ChannelInformation> lookup,
|
|
TickEventHandler tickEventHandler)
|
|
{
|
|
var index = 0;
|
|
foreach (var channel in test.Channels)
|
|
{
|
|
if (!lookup.ContainsKey(channel)) { return; }
|
|
var info = lookup[channel];
|
|
try
|
|
{
|
|
for (var i = 0UL; i < info.NumberOfSamples; i++)
|
|
{
|
|
var adc = ReadShort(info.Reader);
|
|
if (adc < info.MinADC) { info.MinADC = adc; }
|
|
else if (adc > info.MaxADC) { info.MaxADC = adc; }
|
|
}
|
|
index++;
|
|
tickEventHandler?.Invoke(this, (50D * index) / (double)test.Channels.Count);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log($"Failed to get Min/Max for file {info.ChannelFileName} - ", ex);
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Readers a single signed short from file
|
|
/// </summary>
|
|
/// <param name="reader"></param>
|
|
/// <returns></returns>
|
|
private short ReadShort(BinaryReader reader)
|
|
{
|
|
try
|
|
{
|
|
var bytes = reader.ReadBytes(2);
|
|
//to get the next sample from the file we just read two bytes and make a short out of it
|
|
//I'm not sure why to use this version rather than alternatives, but the existing code
|
|
//used this method, so I just preserved it here ...
|
|
return (short)((bytes[0] & 0xFFFF) + ((bytes[1] & 0xFFFF) << 8));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log($"Failed to read from file", ex);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// writes out test to given path
|
|
/// </summary>
|
|
/// <param name="pathname"></param>
|
|
/// <param name="id"></param>
|
|
/// <param name="dataFolder"></param>
|
|
/// <param name="test"></param>
|
|
/// <param name="bFiltering"></param>
|
|
/// <param name="includeGroupNameInISOExport"></param>
|
|
/// <param name="fd"></param>
|
|
/// <param name="tmChannel"></param>
|
|
/// <param name="channelNumber"></param>
|
|
/// <param name="beginEventHandler"></param>
|
|
/// <param name="cancelEventHandler"></param>
|
|
/// <param name="endEventHandler"></param>
|
|
/// <param name="tickEventHandler"></param>
|
|
/// <param name="errorEventHandler"></param>
|
|
/// <param name="cancelRequested"></param>
|
|
/// <param name="minStartTime"></param>
|
|
/// <param name="dataCollectionLength"></param>
|
|
public void Write(string pathname,
|
|
string id,
|
|
string dataFolder,
|
|
Test test,
|
|
bool bFiltering,
|
|
bool includeGroupNameInISOExport,
|
|
FilteredData fd,
|
|
Channel tmChannel,
|
|
int channelNumber,
|
|
BeginEventHandler beginEventHandler,
|
|
CancelEventHandler cancelEventHandler,
|
|
EndEventHandler endEventHandler,
|
|
TickEventHandler tickEventHandler,
|
|
ErrorEventHandler errorEventHandler,
|
|
CancelRequested cancelRequested,
|
|
double minStartTime,
|
|
int dataCollectionLength)
|
|
{
|
|
System.Exception caughtException = null;
|
|
try
|
|
{
|
|
if (!Directory.Exists(Path.GetDirectoryName(pathname)))
|
|
{
|
|
_ = Directory.CreateDirectory(Path.GetDirectoryName(pathname));
|
|
}
|
|
var summaryLookup = GetChannelSummaries(test);
|
|
var binaryReaders = GetBinaryReaders(test, summaryLookup);
|
|
GetMinAndMax(test, summaryLookup, tickEventHandler);
|
|
tickEventHandler?.Invoke(this, 50D);
|
|
CloseAndDisposeReaders(binaryReaders);
|
|
string tmatsDoc = UseAnalogFormat ? GetTMATSAnalog(test, summaryLookup) : GetTMATSPCM(test, summaryLookup);
|
|
GetTimeStamp(test, out var nanoseconds, out var seconds);
|
|
var channelsCount = test.Channels.Count;
|
|
|
|
binaryReaders = GetBinaryReaders(test, summaryLookup);
|
|
|
|
if (UseAnalogFormat)
|
|
{
|
|
Chapter10File.WriteFileAnalog(tmatsDoc,
|
|
(int chIdx) =>
|
|
{
|
|
return ReadShort(binaryReaders[chIdx]);
|
|
},
|
|
(int chIdx) => (long)summaryLookup[test.Channels[chIdx]].NumberOfSamples,
|
|
channelsCount, nanoseconds, seconds, test.Modules[0].SampleRateHz,
|
|
IncludeSecondaryHeader, pathname, tickEventHandler, this);
|
|
}
|
|
else
|
|
{
|
|
Chapter10File.WriteFilePCM(tmatsDoc,
|
|
(int chIdx) => { return ReadShort(binaryReaders[chIdx]); },
|
|
(int chIdx) => (long)summaryLookup[test.Channels[chIdx]].NumberOfSamples,
|
|
channelsCount, nanoseconds, seconds, test.Modules[0].SampleRateHz,
|
|
IncludeSecondaryHeader, pathname, tickEventHandler, this);
|
|
}
|
|
|
|
CloseAndDisposeReaders(binaryReaders);
|
|
tickEventHandler?.Invoke(this, 100D);
|
|
}
|
|
catch (IOException ioException)
|
|
{
|
|
if (ioException.HResult == -2147024816)
|
|
{
|
|
var msg = $"failed to create file, check that file isn't currently open: {pathname}";
|
|
APILogger.Log(msg, ioException);
|
|
caughtException = new IOException(msg, ioException);
|
|
}
|
|
else
|
|
{
|
|
APILogger.Log("encountered problem writing Ch10 file", pathname, ioException);
|
|
caughtException = ioException;
|
|
}
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
APILogger.Log("encountered problem writing Ch10 file", pathname, ex);
|
|
caughtException = ex;
|
|
}
|
|
finally
|
|
{
|
|
tickEventHandler?.Invoke(this, 100D);
|
|
endEventHandler?.Invoke(this);
|
|
if (null != caughtException)
|
|
{
|
|
errorEventHandler?.Invoke(this, caughtException);
|
|
}
|
|
}
|
|
}
|
|
private const int DATA_CHANNEL_ID = 3;
|
|
/// <summary>
|
|
/// returns a string with multiple lines for a single channel for a PCM TMATS file
|
|
/// </summary>
|
|
private static string GetTMATSChannelPCM(Test test, IReadOnlyDictionary<Channel, ChannelInformation> summaryLookup)
|
|
{
|
|
var sb = new StringBuilder();
|
|
var baseText = System.IO.File.ReadAllText(@"TMTTemplates\S6ATMTTemplate_PCM_ExportChannel.tmt");
|
|
for ( var i = 0; i< test.Channels.Count; i++)
|
|
{
|
|
sb.AppendLine(GetTMATSChannelPCM(test, summaryLookup, i, baseText));
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// returns a string with multiple lines for a single channel for a PCM TMATS file
|
|
/// <summary>
|
|
private static string GetTMATSChannelPCM(Test test, IReadOnlyDictionary<Channel, ChannelInformation> summaryLookup, int channelIdx,
|
|
string unmodifiedText)
|
|
{
|
|
//we'll return the basetext, but just make it clear the original string isn't modified, strings are immutable and we
|
|
//are creating new strings and we're holding onto the old string
|
|
var baseText = unmodifiedText;
|
|
var channel = test.Channels[channelIdx];
|
|
try
|
|
{
|
|
var summary = summaryLookup[channel];
|
|
if (channel is AnalogInputChannel aic)
|
|
{
|
|
var ds = SliceRaw.File.Reader.GetDataScaler(aic);
|
|
var eu = aic.EngineeringUnits?.Trim() ?? "";
|
|
var scaler = ds.GetAdcToEuScalingFactor();
|
|
//we want 0 * ds = ds.GetEU(0), but the way to do that is to add in ds.GetEU(0)
|
|
//so that's the offset to add back in ... I'm not sure why analog is using a different formula
|
|
var offset = ds.GetEU(0);
|
|
var minEU = ds.GetEU(summary.MinADC);
|
|
var maxEU = ds.GetEU(summary.MaxADC);
|
|
var channelName = GetChannelName(channel);
|
|
baseText = baseText.Replace("{CHANNEL NUMBER}", $"{1 + channelIdx}");
|
|
baseText = baseText.Replace("{CHANNEL NAME}", channelName);
|
|
baseText = baseText.Replace("{CHANNEL OFFSET EU}", $"{offset:0.0000}");
|
|
baseText = baseText.Replace("{CHANNEL SCALEFACTOR EU}", $"{scaler:0.0000}");
|
|
baseText = baseText.Replace("{CHANNEL EU}", PrepareOutput(eu));
|
|
baseText = baseText.Replace("{CHANNEL MAX RANGE EU}", $"{maxEU:0.0000}");
|
|
baseText = baseText.Replace("{CHANNEL MIN RANGE EU}", $"{minEU:0.0000}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log($"Failed to get TMATS for channel: {channelIdx} - {channel.ChannelName2}", ex);
|
|
}
|
|
return baseText;
|
|
}
|
|
private static string GetTMATSChannelsAnalog(Test test, IReadOnlyDictionary<Channel, ChannelInformation> summaryLookup)
|
|
{
|
|
var sb = new StringBuilder();
|
|
|
|
sb.AppendLine(@"R-1\COM:--------------------- Start of channels ---------------------;");
|
|
|
|
for (var i = 0; i < test.Channels.Count; i++)
|
|
{
|
|
var channel = test.Channels[i];
|
|
try
|
|
{
|
|
var summary = summaryLookup[channel];
|
|
var ds = new DataScaler();
|
|
var eu = "EU";
|
|
if (channel is AnalogInputChannel aic)
|
|
{
|
|
ds = SliceRaw.File.Reader.GetDataScaler(aic);
|
|
eu = aic.EngineeringUnits?.Trim() ?? "";
|
|
}
|
|
var channelName = PrepareOutput(GetChannelName(channel));
|
|
sb.Append(GetTMATSChannel(channelName, summary.MinADC, summary.MaxADC, 1 + i, ds, eu));
|
|
sb.AppendLine();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log($"Failed to get TMATS for channel: {i} - {channel.ChannelName2}", ex);
|
|
}
|
|
}
|
|
|
|
sb.AppendLine(@"R-1\COM:--------------------- End of channels ---------------------;");
|
|
sb.AppendLine(@"R-1\COM:--------------------- End of TMATS ---------------------;");
|
|
|
|
return sb.ToString();
|
|
}
|
|
private static string GetTMATSChannel(string channelName, short ADCMin, short ADCMax, int channelNumber, DataScaler ds,
|
|
string eu)
|
|
{
|
|
var baseText = System.IO.File.ReadAllText(@"TMTTemplates\S6ATMTTemplate_ANALOG_ExportChannel.tmt");
|
|
|
|
baseText = baseText.Replace("{CHANNEL_NUMBER}", $"{channelNumber}");
|
|
baseText = baseText.Replace("{CHANNEL_NAME}", channelName);
|
|
|
|
var scaler = ds.GetAdcToEuScalingFactor();
|
|
var adcToEU = ds.GetAdcToEuScalingFactor();
|
|
var midPointRemoval = adcToEU * Constants.ADC_MIDPOINT;
|
|
|
|
//the scaler is already aware of datazerolevelADC, so just get 0 and datazerolevel is applied, as is
|
|
//initial eu or user offset
|
|
var offset = ds.GetEU(0) - midPointRemoval;
|
|
var minEU = ds.GetEU(ADCMin);
|
|
var maxEU = ds.GetEU(ADCMax);
|
|
|
|
baseText = baseText.Replace("{CHANNEL_OFFSETEU}", $"{offset}");
|
|
baseText = baseText.Replace("{CHANNEL_SCALEFACTOREU}", $"{scaler}");
|
|
baseText = baseText.Replace("{CHANNEL_EU}", PrepareOutput(eu));
|
|
baseText = baseText.Replace("{CHANNEL_MAXRANGEEU}", $"{maxEU}");
|
|
baseText = baseText.Replace("{CHANNEL_MINRANGEEU}", $"{minEU}");
|
|
|
|
return baseText;
|
|
}
|
|
private static string PrepareOutput(string s)
|
|
{
|
|
if (string.IsNullOrEmpty(s)) { return string.Empty; }
|
|
return s.Replace(' ', '_');
|
|
}
|
|
/// <summary>
|
|
/// returns the entire TMATS document as a string for a PCM export
|
|
/// <summary>
|
|
private static string GetTMATSPCM(Test test, IReadOnlyDictionary<Channel, ChannelInformation> summaryLookup)
|
|
{
|
|
var sb = new StringBuilder();
|
|
var baseText = System.IO.File.ReadAllText(@"TMTTemplates\S6ATMTTemplate_PCM_ExportBase.tmt");
|
|
|
|
baseText = baseText.Replace("{NAME OF PROGRAM}", "DataPRO");
|
|
baseText = baseText.Replace("{TEST ID}", test.Modules[0].SerialNumber);
|
|
baseText = baseText.Replace("{STREAM TIME FORMAT}", "2");
|
|
baseText = baseText.Replace("{DAS SERIAL NUMBER}", test.Modules[0].SerialNumber);
|
|
int channelCount = test.Modules.Sum(m => m.Channels.Count);
|
|
var bitsPerFrame = 32 + 16 * channelCount;
|
|
baseText = baseText.Replace("{DAS BIT RATE}", $"{bitsPerFrame * test.Modules[0].SampleRateHz:0}");
|
|
var now = DateTime.UtcNow;
|
|
baseText = baseText.Replace("{CREATE DATE}", $"{now.Year:0000}-{now.Month:00}-{now.Day:00} {now.Hour:00}:{now.Minute:00}:{now.Second:00}");
|
|
baseText = baseText.Replace("{DAS SAMPLE RATE}", $"{test.Modules[0].SampleRateHz}");
|
|
baseText = baseText.Replace("{NUMBER OF CHANNELS}", $"{channelCount}");
|
|
baseText = baseText.Replace("{NUMBER OF WORDS}", $"{1 + channelCount}");
|
|
baseText = baseText.Replace("{NUMBER OF BITS}", $"{32 + 16*channelCount}");
|
|
sb.Append(baseText);
|
|
sb.Append(GetTMATSChannelPCM(test, summaryLookup));
|
|
return sb.ToString();
|
|
}
|
|
private string GetTMATSAnalog(Test test, IReadOnlyDictionary<Channel, ChannelInformation> summaryLookup)
|
|
{
|
|
var sb = new StringBuilder();
|
|
var baseText = System.IO.File.ReadAllText(@"TMTTemplates\S6ATMTTemplate_ANALOG_ExportBase.tmt");
|
|
|
|
baseText = baseText.Replace("{NAME OF PROGRAM}", PrepareOutput(GetApplicationVersion()));
|
|
baseText = baseText.Replace("{TEST ID}", PrepareOutput(test.Id));
|
|
var now = DateTime.UtcNow;
|
|
baseText = baseText.Replace("{CREATE DATE}", $"{now.Year:0000}-{now.Month:00}-{now.Day:00} {now.Hour:00}:{now.Minute:00}:{now.Second:00}");
|
|
baseText = baseText.Replace("{UDP STREAM DATA CHANNEL ID}", $"{DATA_CHANNEL_ID}");
|
|
baseText = baseText.Replace("{DAS SAMPLE RATE}", $"{test.Modules[0].SampleRateHz}");
|
|
baseText = baseText.Replace("{NUMBER_OF_CHANNELS}", $"{test.Modules.Sum(m => m.Channels.Count)}");
|
|
sb.Append(baseText);
|
|
sb.AppendLine();
|
|
sb.Append(GetTMATSChannelsAnalog(test, summaryLookup));
|
|
return sb.ToString();
|
|
}
|
|
|
|
private static string GetApplicationVersion()
|
|
{
|
|
var v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
|
|
return string.Format("DataPRO {0}.{1:00}.{2:00000}", v.Major, v.Minor, v.Build);
|
|
}
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// constructs the writer with a given file and encoding
|
|
/// </summary>
|
|
/// <param name="fileType"></param>
|
|
/// <param name="encoding"></param>
|
|
internal Writer(File fileType, int encoding)
|
|
: base(fileType, encoding)
|
|
{
|
|
WriterParent = fileType;
|
|
}
|
|
|
|
/// <summary>
|
|
/// initializes the writer
|
|
/// </summary>
|
|
/// <param name="pathname"></param>
|
|
/// <param name="id"></param>
|
|
/// <param name="dataFolder"></param>
|
|
/// <param name="test"></param>
|
|
/// <param name="bFiltering"></param>
|
|
/// <param name="includeGroupNameInISOExport"></param>
|
|
/// <param name="fd"></param>
|
|
/// <param name="tmChannel"></param>
|
|
/// <param name="channelNumber"></param>
|
|
/// <param name="beginEventHandler"></param>
|
|
/// <param name="cancelEventHandler"></param>
|
|
/// <param name="endEventHandler"></param>
|
|
/// <param name="tickEventHandler"></param>
|
|
/// <param name="errorEventHandler"></param>
|
|
/// <param name="cancelRequested"></param>
|
|
public void Initialize(string pathname,
|
|
string id,
|
|
string dataFolder,
|
|
Test test,
|
|
bool bFiltering,
|
|
bool includeGroupNameInISOExport,
|
|
FilteredData fd,
|
|
Channel tmChannel,
|
|
int channelNumber,
|
|
BeginEventHandler beginEventHandler,
|
|
CancelEventHandler cancelEventHandler,
|
|
EndEventHandler endEventHandler,
|
|
TickEventHandler tickEventHandler,
|
|
ErrorEventHandler errorEventHandler,
|
|
CancelRequested cancelRequested)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|