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

View File

@@ -0,0 +1,173 @@
/*
* TDAS.File.Writer.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System;
using System.IO;
using System.Linq;
using System.Text;
using DTS.Common.Utilities.Logging;
namespace DTS.Serialization.TDAS
{
// *** see TDAS.File.cs ***
public partial class File
{ ///
/// <summary>
/// Utility object for serializing <see cref="DTS.Serialization.Test"/>s to disk
/// in the Diadem
/// </summary>
///
public class Writer : Writer<File>, IWriter<Test>
{
/// <summary>
/// Initialize an instance of the Diadem.File.Writer class.
/// </summary>
///
/// <param name="fileType">
/// The associated <see cref="DTS.SErialization.Diadem.File"/> object.
/// </param>
///
internal Writer(File fileType, int encoding)
: base(fileType, encoding)
{
}
/// <summary>
/// Write the specified test to the specified pathname.
/// </summary>
///
/// <param name="pathname">
/// The <see cref="string"/> pathname to which the specified test should be serialized.
/// </param>
///
/// <param name="test">
/// The <see cref="DTS.Serialization.Test"/> to be written out.
/// </param>
///
public void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)
{
throw new NotSupportedException("TDAS::File::Writer Write(pathname, id, test, bFiltering) not supported");
}
private const string TLF_FILE_BACKUP_EXTENSION = ".TLF PreTest Backup";
/// <summary>
/// Write the representation file/files of the specified DTS.Serialization.Test
/// at the given pathname.
/// </summary>
///
/// <param name="targetPathname">
/// The <see cref="string"/> pathname of the specified object's resulting file
/// representation.
/// </param>
///
public void Write(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,
double minStartTime,
int dataCollectionLength)
{
System.Exception exception = null;
try
{
beginEventHandler?.Invoke(this, Convert.ToUInt32(test.Channels.Count));
var tlf = new TLF(pathname, test, id);
using (var sw = new StreamWriter(pathname, false, Encoding.Default))
{
tlf.Serialize(sw);
sw.Flush();
sw.Close();
}
var tlfFileInfo = new FileInfo(pathname);
var backupTLFFileName = tlfFileInfo.Name.Replace(tlfFileInfo.Extension, TLF_FILE_BACKUP_EXTENSION);
var backupFilePath = Path.Combine(tlfFileInfo.DirectoryName, backupTLFFileName);
try
{
System.IO.File.Copy(tlfFileInfo.FullName, backupFilePath);
}
catch (Exception ex)
{
APILogger.Log($"Failed to backup file {tlfFileInfo.FullName} to {backupFilePath}", ex);
}
var startingChannel = tlf.LastChannelNumber + 1;
var startingSquibChannel = 901;
var maxSampleRate = test.Channels.Select(ch => ch.ParentModule.SampleRateHz).Max();
for (var i = 0; i < test.Channels.Count; i++)
{
var fi = new FileInfo(pathname);
var newFile = string.Empty;
if ((test.Channels[i] as Test.Module.AnalogInputChannel).IsSquibChannel)
{
newFile = fi.FullName.Replace(fi.Extension, string.Format("{0:000}.BIN", startingSquibChannel));
startingSquibChannel++;
}
else
{
newFile = fi.FullName.Replace(fi.Extension, string.Format("{0:000}.BIN", startingChannel));
startingChannel++;
}
using (var bw = new BinaryWriter(new FileStream(newFile, FileMode.OpenOrCreate)))
{
var bin = new TLFBin(test.Channels[i], maxSampleRate);
bin.Serialize(bw, test.Channels[i]);
bw.Flush();
bw.Close();
}
tickEventHandler?.Invoke(this, Convert.ToDouble(i + 1));
}
}
catch (System.Exception ex)
{
exception = ex;
APILogger.Log("encountered problem writing TDAS test files", ex);
}
if (null != errorEventHandler && null != exception)
{
endEventHandler(this);
errorEventHandler(this, exception);
}
else if (null != exception) { throw exception; }
else
{
tickEventHandler?.Invoke(this, 100.0);
endEventHandler?.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)
{
}
}
}
}

View File

@@ -0,0 +1,53 @@
/*
* SoMat.File.cs
*
* Copyright © 2013
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.Serialization.DDAS
{
///
/// <summary>
/// File
/// </summary>
///
public partial class File
: Serialization.File, IWritable<Test>
{ ///
/// <summary>
/// Initialize an instance of the FtssCsv.File class.
/// </summary>
///
public File()
: base("DDAS")
{
}
/// <summary>
/// Get this file format's extension.
/// </summary>
public static string Extension => ".ddas";
/// <summary>
/// Get the file writer for this file type.
/// </summary>
public IWriter<Test> Exporter
{
get
{
try
{
if (null == _Exporter) { _Exporter = new Writer(this, DefaultEncoding); }
return _Exporter;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting exporter", ex);
}
}
}
private IWriter<Test> _Exporter = null;
}
}

View File

@@ -0,0 +1,367 @@
using DTS.Serialization.IRIGCH10.Enums;
using System;
using System.Collections;
namespace DTS.Serialization.IRIGCH10
{
/// <summary>
/// implements the PCM/Pulse Control Modulation packet for CH 10
/// </summary>
public class PCMPacket : AbstractDataPacket, IDataPacket
{
private byte [] ChannelSpecificData;
public PCMPacket()
: base(DataFileDataTypes.PCMDataFormat1)
{
ChannelSpecificData = new byte[4];
_dataBytes = new byte[ChannelSpecificData.Length];
}
/// <summary>
/// Intra-Packet Header (IPH). (Bit 30) indicates if Intra-Packet Headers (IntraPacket Time Stamp and Intra-Packet Data Header) are inserted before each
/// minor frame. Intra-Packet Headers are only optional because of the mode
/// selection. This determines whether Intra-Packet Headers are included or
/// omitted.
/// false = Intra-Packet Headers are omitted for Throughput Mode.
/// true = Intra-Packet Headers are required for Packed Data and Unpacked Data
/// modes.
/// </summary>
public bool IntraPacketHeader
{
get
{
var bitArray = new BitArray(ChannelSpecificData);
return bitArray[30];
}
set
{
var bitArray = new BitArray(ChannelSpecificData);
bitArray[30] = value;
bitArray.CopyTo(ChannelSpecificData, 0);
}
}
/// <summary>
/// Major Frame Indicator (MA). (Bit 29) indicates if the first word in the packet is
/// the beginning of a major frame. Not valid for Throughput Mode.
/// false = First word is not the beginning of a major frame.
/// true = First word is the beginning of a major frame.
/// </summary>
public bool MajorFrameIndicator
{
get
{
var bitArray = new BitArray(ChannelSpecificData);
return bitArray[29];
}
set
{
var bitArray = new BitArray(ChannelSpecificData);
bitArray[29] = value;
bitArray.CopyTo(ChannelSpecificData, 0);
}
}
/// <summary>
/// Minor Frame Indicator (MI). (Bit 28) indicates if the first word in the packet is
/// the beginning of a minor frame. Not valid for Throughput Mode.
/// false = First word is not the beginning of a minor frame.
/// true = First word is the beginning of a minor frame.
/// </summary>
public bool MinorFrameIndicator
{
get
{
var bitArray = new BitArray(ChannelSpecificData);
return bitArray[28];
}
set
{
var bitArray = new BitArray(ChannelSpecificData);
bitArray[28] = value;
bitArray.CopyTo(ChannelSpecificData, 0);
}
}
/// <summary>
/// Indicate Minor Frame Status
/// true = Minor Frame Lock
/// false = Minor Frame Check (after losing lock)
/// </summary>
public bool MinorFrameLockStatus
{
get
{
var bitArray = new BitArray(ChannelSpecificData);
return bitArray[27] && bitArray[26];
}
set
{
var bitArray = new BitArray(ChannelSpecificData);
bitArray[27] = true;
bitArray[26] = value;
bitArray.CopyTo(ChannelSpecificData, 0);
}
}
/// <summary>
/// true - Major Frame Lock
/// false - Major Frame Check (after losing Lock)
/// </summary>
public bool MajorFrameStatus
{
get
{
var bitArray = new BitArray(ChannelSpecificData);
return bitArray[25] && bitArray[24];
}
set
{
var bitArray = new BitArray(ChannelSpecificData);
bitArray[25] = true;
bitArray[24] = value;
bitArray.CopyTo(ChannelSpecificData, 0);
}
}
/// <summary>
/// true = 32Bit Alignment Mode
/// false = 16Bit Alignment Mode
/// </summary>
public bool AlignmentMode
{
get
{
var bitArray = new BitArray(ChannelSpecificData);
return bitArray[21];
}
set
{
var bitArray = new BitArray(ChannelSpecificData);
bitArray[21] = value;
bitArray.CopyTo(ChannelSpecificData, 0);
}
}
/// <summary>
/// Throughput DataMode enabled or not
/// </summary>
public bool ThroughputDataMode
{
get
{
var bitArray = new BitArray(ChannelSpecificData);
return bitArray[20];
}
set
{
var bitArray = new BitArray(ChannelSpecificData);
bitArray[20] = value;
bitArray.CopyTo(ChannelSpecificData, 0);
}
}
public bool PackedData
{
get
{
var bitArray = new BitArray(ChannelSpecificData);
return bitArray[19];
}
set
{
var bitArray = new BitArray(ChannelSpecificData);
bitArray[19] = value;
bitArray.CopyTo(ChannelSpecificData, 0);
}
}
public bool UnpackedData
{
get
{
var bitArray = new BitArray(ChannelSpecificData);
return bitArray[18];
}
set
{
var bitArray = new BitArray(ChannelSpecificData);
bitArray[18] = value;
bitArray.CopyTo(ChannelSpecificData, 0);
}
}
/// <summary>
/// contains an 18-bit binary value
/// representing the Word offset into the major frame for the first data word in the
/// packet. Not valid for Packed or Throughput Mode.
/// </summary>
public byte[] SyncOffset
{
get
{
var output = new byte[2];
var bitArray = new BitArray(ChannelSpecificData);
var bitArray2 = new BitArray(output);
for (int i = 0; i <= 17; i++)
{
bitArray2[i] = bitArray[i];
}
bitArray2.CopyTo(output, 0);
return output;
}
set
{
var bitArray = new BitArray(ChannelSpecificData);
var bitArray2 = new BitArray(value);
for (int i = 0; i <= 17; i++)
{
bitArray[i] = bitArray2[i];
}
bitArray.CopyTo(ChannelSpecificData, 0);
}
}
public readonly byte[] FrameSync = new byte[] { 0x90, 0xEB };
//private readonly byte[] FrameSync = new byte[] { 0x90, 0xEB, 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x90, 0xEB };
/// <summary>
/// adds data in unpacked 16 bit alignment into the data buffer, resizing as needed
/// </summary>
/// <param name="data"></param>
public void AddUnpacked16BitData(ushort[] data, long timeStamp, bool bFirst)
{
var intraPacketBytes = GetIntraPacketTimeStampBytes(timeStamp);
var intraHeaderBytes = GetIntraPacketHeader();
var insertSpot = 0;
//for some reason the spec seems to call out a different first order than all subsequent data sequences.
//the first sequence has a timestamp at the front, while all subsequent do not, but have a trailer timestamp.
if (bFirst)
{
var newBuffer = new byte[_dataBytes.Length + data.Length * 2 + FrameSync.Length + intraPacketBytes.Length + intraHeaderBytes.Length];
Buffer.BlockCopy(_dataBytes, 0, newBuffer, insertSpot, _dataBytes.Length);
insertSpot += _dataBytes.Length;
Buffer.BlockCopy(intraPacketBytes, 0, newBuffer, insertSpot, intraPacketBytes.Length);
insertSpot += intraPacketBytes.Length;
Buffer.BlockCopy(intraHeaderBytes, 0, newBuffer, insertSpot, intraHeaderBytes.Length);
insertSpot += intraHeaderBytes.Length;
Buffer.BlockCopy(FrameSync, 0, newBuffer, insertSpot, FrameSync.Length);
insertSpot += FrameSync.Length;
Buffer.BlockCopy(data, 0, newBuffer, insertSpot, data.Length * 2);
}
else
{
var newBuffer = new byte[_dataBytes.Length + data.Length * 2 + intraPacketBytes.Length + intraHeaderBytes.Length];
Buffer.BlockCopy(_dataBytes, 0, newBuffer, insertSpot, _dataBytes.Length);
insertSpot += _dataBytes.Length;
Buffer.BlockCopy(data, 0, newBuffer, insertSpot, data.Length * 2);
insertSpot += data.Length * 2;
Buffer.BlockCopy(intraPacketBytes, 0, newBuffer, insertSpot, intraPacketBytes.Length);
insertSpot += intraPacketBytes.Length;
Buffer.BlockCopy(intraHeaderBytes, 0, newBuffer, insertSpot, intraHeaderBytes.Length);
}
}
/// <summary>
/// adds data in unpacked 16 bit alignment into the data buffer, resizing as needed
/// </summary>
/// <param name="data"></param>
public void AddPacked16BitData(ushort[] data, long timeStamp, bool bFirst)
{
var intraPacketBytes = GetIntraPacketTimeStampBytes(timeStamp);
var intraHeaderBytes = GetIntraPacketHeader();
var insertSpot = 0;
//for some reason the spec seems to call out a different first order than all subsequent data sequences.
//the first sequence has a timestamp at the front, while all subsequent do not, but have a trailer timestamp.
if (bFirst)
{
var newBuffer = new byte[_dataBytes.Length + data.Length * 2 + FrameSync.Length + intraPacketBytes.Length + intraHeaderBytes.Length];
Buffer.BlockCopy(_dataBytes, 0, newBuffer, insertSpot, _dataBytes.Length);
insertSpot += _dataBytes.Length;
Buffer.BlockCopy(intraPacketBytes, 0, newBuffer, insertSpot, intraPacketBytes.Length);
insertSpot += intraPacketBytes.Length;
Buffer.BlockCopy(intraHeaderBytes, 0, newBuffer, insertSpot, intraHeaderBytes.Length);
insertSpot += intraHeaderBytes.Length;
Buffer.BlockCopy(FrameSync, 0, newBuffer, insertSpot, FrameSync.Length);
insertSpot += FrameSync.Length;
Buffer.BlockCopy(data, 0, newBuffer, insertSpot, data.Length * 2);
}
else
{
var newBuffer = new byte[_dataBytes.Length + data.Length * 2 + intraPacketBytes.Length + intraHeaderBytes.Length];
Buffer.BlockCopy(_dataBytes, 0, newBuffer, insertSpot, _dataBytes.Length);
insertSpot += _dataBytes.Length;
Buffer.BlockCopy(data, 0, newBuffer, insertSpot, data.Length * 2);
insertSpot += data.Length * 2;
Buffer.BlockCopy(intraPacketBytes, 0, newBuffer, insertSpot, intraPacketBytes.Length);
insertSpot += intraPacketBytes.Length;
Buffer.BlockCopy(intraHeaderBytes, 0, newBuffer, insertSpot, intraHeaderBytes.Length);
}
}
private byte [] GetIntraPacketHeader()
{
var array = new BitArray(new byte[2]);
//bits 15-14 minor frame status
//00,01 reserved
//10 minor frame check
//11 minor frame lock
//bits 13-12 major frame status
// 00 - major frame not locked
// 01 - reserved
// 10 major frame check
// 11 major frame lock
array.Set(15, true);
array.Set(14, true);
array.Set(12, true);
array.Set(13, true);
var output = new byte[2];
array.CopyTo(output, 0);
return output;
}
private byte [] GetIntraPacketTimeStampBytes(long timeStamp)
{
var output = new byte[8];
var stamp = IRIGCH10.PacketHeader.GetRTCBytes(timeStamp);
Buffer.BlockCopy(output, 0, stamp, 0, stamp.Length);
return output;
}
/// <summary>
/// adds data in throughput mode to the packet, resizing the data buffer in the process
/// [throughput mode as opposed to a packed/or aligned mode]
/// </summary>
/// <param name="data"></param>
//public void AddThroughputData(ushort[] data)
//{
// var newBuffer = new byte[_dataBytes.Length + data.Length * 2 + FrameSync.Length];
// Buffer.BlockCopy(_dataBytes, 0, newBuffer, 0, _dataBytes.Length);
// Buffer.BlockCopy(FrameSync, 0, newBuffer, _dataBytes.Length, FrameSync.Length);
// Buffer.BlockCopy(data, 0, newBuffer, _dataBytes.Length + FrameSync.Length, data.Length * 2);
// _dataBytes = newBuffer;
//}
public override void ComputeCheckSum()
{
RefreshChannelSpecificDataInDataBytes();
base.ComputeCheckSum();
}
public override byte[] GetBytes()
{
RefreshChannelSpecificDataInDataBytes();
return base.GetBytes();
}
private void RefreshChannelSpecificDataInDataBytes()
{
//make sure ChannelSpecificData is set ...
Buffer.BlockCopy(ChannelSpecificData, 0, _dataBytes, 0, ChannelSpecificData.Length);
}
}
}

View File

@@ -0,0 +1,912 @@
/*
* FtssTsv.File.Writer.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.IO;
using System.Text;
using DTS.Common.DAS.Concepts;
using DTS.Common.DAS.Concepts.DAS.Channel;
using DTS.Common.Utilities;
using DTS.Common.Utilities.DotNetProgrammingConstructs;
using DTS.Common.Utilities.Logging;
using DTS.Common;
using DTS.Common.Enums.Sensors;
using DTS.Common.Utils;
namespace DTS.Serialization.FtssTsv
{
// *** see FtssTsv.File.cs ***
public partial class File
{ ///
/// <summary>
/// Utility object for serializing <see cref="DTS.Serialization.Test"/>s to disk
/// in the FTSS CSV format.
/// </summary>
///
public partial class Writer : Writer<File>, IWriter<Test>
{
/// <summary>
/// Initialize an instance of the FtssTsv.File.Writer class.
/// </summary>
///
/// <param name="fileType">
/// The associated <see cref="DTS.SErialization.FtssTsv.File"/> object.
/// </param>
///
internal Writer(File fileType, int encoding)
: base(fileType, encoding)
{
}
/// <summary>
/// The different export modes that should theoretically be supported by this format.
/// </summary>
public enum ExportMode
{
FtssExcel,
Ttc,
Standard,
}
private const string NUMBER_FORMAT = "F8";
private const string TAB_LIST_SEPARATOR = "\t"; //Tab
/// <summary>
/// Get/set the current CSV export format.
/// </summary>
public ExportMode CurrentExportMode
{
get => _CurrentExportMode.Value;
set => _CurrentExportMode.Value = value;
}
private readonly Property<ExportMode> _CurrentExportMode
= new Property<ExportMode>(
typeof(Writer).Namespace + ".File.Writer.CurrentExportMode",
ExportMode.FtssExcel,
true
);
/// <summary>
/// Notify <see cref="DTS.Serialization.BeginEventHandler"/> subscribers that the write
/// is starting.
/// </summary>
public event BeginEventHandler OnBegin;
/// <summary>
/// Notify <see cref="DTS.Serialization.EndEventHandler"/> subscribers that the write
/// is finished.
/// </summary>
public event EndEventHandler OnEnd;
/// <summary>
/// Notify <see cref="DTS.Serialization.TickEventHandler"/> subscribers that we are one
/// tick closer to write completion.
/// </summary>
public event TickEventHandler OnTick;
/// <summary>
/// notify subscribers that the write was cancelled
/// </summary>
public event CancelEventHandler OnCancel;
/// <summary>
/// notify subscribers that the writer encountered fatal error
/// </summary>
public event ErrorEventHandler OnError;
/// <summary>
/// The number of data samples that need to be written for a "tick" to be dispatched.
/// </summary>
private int DataSamplesPerTick => 1000;
/// <summary>
/// Return the number of data to be written per "tick".
/// </summary>
/// <param name="channel"></param>
/// <returns></returns>
private uint GetChannelTicks(Test.Module.Channel channel)
{
try
{ //
// Most of our wait time will be spent writing data, so we need to give
// the process a little finer granularity.
//
return (uint)(channel.PersistentChannelInfo.Length / DataSamplesPerTick);
}
catch (System.Exception ex)
{
throw new Exception("encountered problem determining number of status ticks for channel " + (null != channel ? "\"" + channel.Number.ToString() + "\"" : "<NULL>"), ex);
}
}
/// <summary>
/// Get/set the filtered channel data. If this list is supplied, the corresponding test
/// channel data values will be supplied from this list.
/// </summary>
public List<FilteredData> FilteredChannelData
{
get => _FilteredChannelData.Value;
set => _FilteredChannelData.Value = value;
}
private readonly Property<List<FilteredData>> _FilteredChannelData
= new Property<List<FilteredData>>(
"FilteredChannelData",
new List<FilteredData>(),
true
);
public string DataChannelFilename { get; set; }
public string LaboratoryName { get; set; }
public string LaboratoryContactName { get; set; }
public string LaboratoryContactPhone { get; set; }
public string LaboratoryContactEmail { get; set; }
public string TestEngineerName { get; set; }
public string TestEngineerPhone { get; set; }
public string TestEngineerEmail { get; set; }
public int NumChannelsWritten { get; set; }
public bool UseISOCodeFilterMapping { get; set; }
public bool UseZeroForUnfiltered { get; set; }
/// <summary>
/// Write the specified test to the specified pathname.
/// </summary>
///
/// <param name="pathname">
/// The <see cref="string"/> pathname to which the specified test should be serialized.
/// </param>
///
/// <param name="test">
/// The <see cref="DTS.Serialization.Test"/> to be written out.
/// </param>
///
public void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)
{
try
{
Write(pathname, id, null, test, bFiltering, includeGroupNameInISOExport, null, null, 0, null, null, null, null, null, null, minStartTime, dataCollectionLength);
}
catch (System.Exception ex)
{
throw new Exception("encountered problem non-event notified writing test", ex);
}
}
/// <summary>
/// Write the representation file/files of the specified DTS.Serialization.Test
/// at the given pathname.
/// </summary>
///
/// <param name="targetPathname">
/// The <see cref="string"/> pathname of the specified object's resulting file
/// representation.
/// </param>
///
public void Write(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,
double minStartTime,
int dataCollectionLength)
{
System.Exception exception = null;
try
{
//this.OnBegin += beginEventHandler; //Since we are called once for every file, we don't want to continually set progress to 0%
//this.OnEnd += endEventHandler; //Nor do we want to increment the number of exports that have finished
OnTick += tickEventHandler;
OnCancel += cancelEventHandler;
OnError += errorEventHandler;
// Compute the total number of write ticks that will be dispatched during this
// write, and let the caller know that we're underway.
uint channelTicks = 0;
uint totalWriteTicksNeeded = 0;
if (test.Channels.Count > 0)
{
channelTicks = GetChannelTicks(test.Channels[0]);
totalWriteTicksNeeded = channelTicks * (uint)test.Channels.Count;
}
var totalWriteTicksDispatched = channelTicks * (uint)NumChannelsWritten;
APILogger.Log("opening ", pathname);
//DateTime start = DateTime.Now;
if (!Directory.Exists(Path.GetDirectoryName(pathname)))
{
Directory.CreateDirectory(Path.GetDirectoryName(pathname));
}
if (System.IO.File.Exists(pathname))
{
FileUtils.DeleteFileOrMove(pathname, APILogger.Log);
}
using (var fileWriter = new StreamWriter(pathname, false, Encoding.Default))
{
//List<Test.Module.Channel> exportChannels = test.Channels;
switch (CurrentExportMode)
{
case ExportMode.FtssExcel:
WriteChannelInfo(fileWriter,
id,
test,
FilteredChannelData,
pathname,
tickEventHandler,
totalWriteTicksNeeded,
ref totalWriteTicksDispatched,
cancelRequested,
channelNumber,
minStartTime,
dataCollectionLength);
break;
default:
throw new NotSupportedException("FtssTsv::File::Writer ExportMode not supported: " + CurrentExportMode.ToString());
}
}
}
catch (System.Exception ex)
{
APILogger.Log("encountered problem writing TSV test files", ex);
exception = new Exception("encountered problem writing TSV test files", ex);
}
finally
{
if (null != cancelRequested && cancelRequested())
{
OnCancel?.Invoke(this);
}
if (null != exception && null != errorEventHandler)
{
errorEventHandler(this, exception);
}
else if (null != exception)
{
throw exception;
}
}
}
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)
{
}
/// <summary>
/// The various header lines (and associated text) that appear in this file format.
/// </summary>
private enum FtssHeaderLine
{
[Description("Headers")]
Headers = 0,
[Description("Test Date")]
TestDate,
[Description("Test Time")]
TestTime,
[Description("Test ID")]
TestId,
[Description("Test Description")]
TestDescription,
[Description("Laboratory Name")]
LaboratoryName,
[Description("Laboratory Contact Name")]
LaboratoryContactName,
[Description("Laboratory Contact Phone")]
LaboratoryContactPhone,
[Description("Laboratory Contact Email")]
LaboratoryContactEmail,
[Description("Test Engineer Name")]
TestEngineerName,
[Description("Test Engineer Phone")]
TestEngineerPhone,
[Description("Test Engineer Email")]
TestEngineerEmail,
[Description("Sample Rate (Hz)")]
SampleRate,
[Description("Hardware AA Filter (-3dB)")]
HardwareAntiAliasFilter,
[Description("Data Channel Name")]
DataChannelName,
[Description("ISO Channel Code")]
IsoCode,
[Description("Channel Description")]
ChannelDescription,
[Description("Channel Location")]
ChannelLocation,
[Description("Sensor S/N")]
SensorSerialNumber,
[Description("Software Filter (SAE Class)")]
SoftwareFilter,
[Description("Software Filter (-3dB)")]
SoftwareFilterDb,
[Description("Engineering Unit")]
EngineeringUnits,
[Description("User Comment")]
UserComment,
[Description("Number of Pre-Zero Data Pts")]
PreZero,
[Description("Number of Post-Zero Data Pts")]
PostZero,
[Description("Data Zero (CNTS)")]
DataZero,
[Description("Scale Factor (EU/CNT)")]
ScaleEu,
[Description("Scale Factor (mV/CNT)")]
ScaleMv,
[Description("Data Starts Here")]
DataStart,
[Description("Time")]
Labels,
}
/// <summary>
/// Generate a best-estimate export size for the specified dataset, and check it against the
/// current disk availability stats.
/// </summary>
///
/// <param name="testname">
/// The <see cref="string"/> name of the test to be verified.
/// </param>
///
/// <param name="saveLocation">
/// The <see cref="string"/> name of the target location into which the test must fit.
/// </param>
///
/// <param name="headerLines">
/// An <see cref="System.Collections.Generic.IDictionary<TKey,TValue>"/> containing pairs
/// of header entry name <see cref="string"/>s and corresponding value <see cref="string"/>s.
/// </param>
///
/// <param name="coder">
/// A <see cref="DescriptionAttributeCoder<TargetType>"/> for en/coding
/// <see cref="DTS.Serialization.FtssTsv.File.Writer.FtssHeaderLine"/> header enumerations.
/// </param>
///
/// <param name="channelsWithMeta">
/// A populated <see cref="System.Collections.Generic.List<T>"/> of
/// <see cref="DTS.Serialization.FtssTsv.File.Writer.ChannelWithMeta"/>s generated from
/// the test to be exported.
/// </param>
///
/// <param name="dataCollectionLength">
/// The <see cref="int"/> length of the data collection within this test that is to be
/// exported.
/// </param>
///
/// <param name="minStartTime">
/// The earliest <see cref="double"/> T0-relative start time on any channel within the
/// test to be exported.
/// </param>
///
/// <param name="sampleRate">
/// The <see cref="double"/> sample rate of the test to be exported.
/// </param>
///
private void VerifyExportedFileWillFitOnDisk(
string testname,
string saveLocation,
IDictionary<FtssHeaderLine, List<string>> headerLines,
DescriptionAttributeCoder<FtssHeaderLine> coder,
List<ChannelWithMeta> channelsWithMeta,
int dataCollectionLength,
double minStartTime,
double sampleRate,
CancelRequested cancelRequested
)
{
try
{ //
// Compute the size of the header information.
//
ulong predictedExportSize = 0;
foreach (FtssHeaderLine ftssSizeHeaderLine in Enum.GetValues(typeof(FtssHeaderLine)))
{
if (headerLines.Keys.Contains(ftssSizeHeaderLine))
{
var channelValues = headerLines[ftssSizeHeaderLine];
predictedExportSize += (ulong)(coder.DecodeAttributeValue(ftssSizeHeaderLine).Length + TAB_LIST_SEPARATOR.Length);
foreach (var channelValue in channelValues)
predictedExportSize += (ulong)(channelValue.Length + TAB_LIST_SEPARATOR.Length);
}
}
//
// Compute the size of the data portion.
// this computation is expensive for large data collections, so lets just subsample them for now
// for every 2 million samples collected we'll increase the size of subsamples by 1.
var segmentSize = dataCollectionLength / 2000000;
if (segmentSize < 1) { segmentSize = 1; }
for (var i = 0; i < dataCollectionLength; i += segmentSize)
{
if (null != cancelRequested && cancelRequested()) { break; }
var thisSegmentSize = (ulong)((minStartTime + i * 1.0 / sampleRate).ToString(NUMBER_FORMAT) + TAB_LIST_SEPARATOR).Length;
foreach (var channelWithMeta in channelsWithMeta)
{
if (null != cancelRequested && cancelRequested()) { break; }
var thisChannelsIndexAtCurrentTime = i - (int)((channelWithMeta.StartTime - minStartTime) * channelWithMeta.SampleRate);
thisSegmentSize += thisChannelsIndexAtCurrentTime >= 0 && thisChannelsIndexAtCurrentTime < channelWithMeta.Channel.PersistentChannelInfo.Length ?
9U : 1U;
}
var segmentJump = i + segmentSize > dataCollectionLength ? dataCollectionLength - i : segmentSize;
predictedExportSize += thisSegmentSize * (ulong)segmentJump;
}
predictedExportSize *= sizeof(char);
// Get the stats on available disk space.
var errorcode = DiskUtility.GetDiskFreeSpaceEx(saveLocation, out ulong freeBytesAvailable, out ulong totalNumberOfBytes, out ulong totalNumberOfFreeBytes);
if (0 != errorcode)
{
// Do the comparison.
if (freeBytesAvailable < predictedExportSize)
{
var bytesNeeded = DiskUtility.GetHumanReadableBytes(predictedExportSize);
var bytesAvailable = DiskUtility.GetHumanReadableBytes(freeBytesAvailable);
throw new UserException("Export requires " + bytesNeeded + " but there are only " + bytesAvailable + " bytes available on \"" + saveLocation + "\"");
}
}
else
{
APILogger.Log("Failed to get free disk space, windows error: ", errorcode);
}
}
catch (System.Exception ex)
{
throw new Exception("encountered problem trying to determing if CSV export of test " + (testname ?? "<NULL>") + " will fit at location " + (saveLocation ?? "<NULL>"), ex);
}
}
/// <summary>
/// Write the specified test to the specified stream.
/// </summary>
///
/// <param name="fileWriter">
/// The <see cref="System.IO.StreamWriter"/> to which the specified test should be serialized.
/// </param>
///
/// <param name="test">
/// The <see cref="DTS.Serialization.Test"/> to be serialized.
/// </param>
///
/// <param name="writeEvent">
/// The <see cref="FtssTsv.File.Writer.EventHandler"/> that should handle write-progress
/// reporting; null if none is to be used.
/// <param name="targetPath">
/// The <see cref="string"/> path that the file writer will be writing to.
/// </param>
///
/// <param name="tickEventHandler">
/// The <see cref="DTS.Serialization.TickEventHandler"/> that will process "tick" events
/// indicating progress during the export procedure.
/// </param>
///
/// <param name="totalWriteTicksNeeded">
/// The total <see cref="uint"/> number of progress ticks that will be issued during the
/// export procedure.
/// </param>
///
/// <param name="totalWriteTicksDispatched">
/// Returns the total <see cref="uint"/> number of tick events that have been dispatched.
/// </param>
///
protected void WriteChannelInfo
(
StreamWriter fileWriter,
string id,
Test test,
List<FilteredData> filteredData,
string targetPath,
TickEventHandler tickEventHandler,
uint totalWriteTicksNeeded,
ref uint totalWriteTicksDispatched,
CancelRequested cancelRequested,
int channelNumber,
double minStartTime,
int dataCollectionLength)
{
try
{
//FB14621: Get the sample rate of the channels we're going to care about (i.e. channels with meta), rather than the whole test/roi
var sampleRate = test.Channels.Find(ch => DataChannelFilename == Path.GetFileName(((Test.Module.AnalogInputChannel)ch).FileName)).ParentModule.SampleRateHz;
if (1 < SubSampleInterval)
{
var ChannelList = test.Channels;
for (var iChannel = 0; iChannel < ChannelList.Count; iChannel++)
{
if (true == Filtered)
{
var SubSample = new NHTSASubSample<double>();
SubSample.data = FilteredChannelData[iChannel].Data;
SubSample.preTriggerSamples = test.Modules[0].TriggerSampleNumbers[0] - test.Modules[0].StartRecordSampleNumber;
SubSample.sampleRate = sampleRate;
SubSample.subSampleInterval = SubSampleInterval;
SubSample.SubSample();
FilteredChannelData[iChannel].Data = SubSample.data;
ChannelList[iChannel].IsSubsampled = true; // I don't think anyone will consume this, but for completeness.
}
else
{
var SubSample = new NHTSASubSample<short>();
SubSample.data = ChannelList[iChannel].PersistentChannelInfo.Data;
SubSample.preTriggerSamples = test.Modules[0].TriggerSampleNumbers[0] - test.Modules[0].StartRecordSampleNumber;
SubSample.sampleRate = sampleRate;
SubSample.subSampleInterval = SubSampleInterval;
SubSample.SubSample();
ChannelList[iChannel].PersistentChannelInfo.Data = SubSample.data;
ChannelList[iChannel].IsSubsampled = true; // I don't think anyone will consume this, but for completeness.
}
}
sampleRate = sampleRate / SubSampleInterval;
}
//
// Initialize the header information.
//
var coder = new DescriptionAttributeCoder<FtssHeaderLine>();
IDictionary<FtssHeaderLine, List<string>> headerLines = new Dictionary<FtssHeaderLine, List<string>>();
headerLines.Add(FtssHeaderLine.Headers, new List<string>());
headerLines.Add(FtssHeaderLine.TestDate, new List<string>());
headerLines.Add(FtssHeaderLine.TestTime, new List<string>());
headerLines.Add(FtssHeaderLine.TestId, new List<string>());
headerLines.Add(FtssHeaderLine.TestDescription, new List<string>());
headerLines.Add(FtssHeaderLine.LaboratoryName, new List<string>());
headerLines.Add(FtssHeaderLine.LaboratoryContactName, new List<string>());
headerLines.Add(FtssHeaderLine.LaboratoryContactPhone, new List<string>());
headerLines.Add(FtssHeaderLine.LaboratoryContactEmail, new List<string>());
headerLines.Add(FtssHeaderLine.TestEngineerName, new List<string>());
headerLines.Add(FtssHeaderLine.TestEngineerPhone, new List<string>());
headerLines.Add(FtssHeaderLine.TestEngineerEmail, new List<string>());
headerLines.Add(FtssHeaderLine.SampleRate, new List<string>());
headerLines.Add(FtssHeaderLine.HardwareAntiAliasFilter, new List<string>());
headerLines.Add(FtssHeaderLine.DataChannelName, new List<string>());
headerLines.Add(FtssHeaderLine.IsoCode, new List<string>());
headerLines.Add(FtssHeaderLine.ChannelDescription, new List<string>());
headerLines.Add(FtssHeaderLine.ChannelLocation, new List<string>());
headerLines.Add(FtssHeaderLine.SensorSerialNumber, new List<string>());
headerLines.Add(FtssHeaderLine.SoftwareFilter, new List<string>());
headerLines.Add(FtssHeaderLine.SoftwareFilterDb, new List<string>());
headerLines.Add(FtssHeaderLine.EngineeringUnits, new List<string>());
headerLines.Add(FtssHeaderLine.UserComment, new List<string>());
headerLines.Add(FtssHeaderLine.PreZero, new List<string>());
headerLines.Add(FtssHeaderLine.PostZero, new List<string>());
headerLines.Add(FtssHeaderLine.DataZero, new List<string>());
headerLines.Add(FtssHeaderLine.ScaleEu, new List<string>());
headerLines.Add(FtssHeaderLine.ScaleMv, new List<string>());
headerLines.Add(FtssHeaderLine.DataStart, new List<string>());
headerLines.Add(FtssHeaderLine.Labels, new List<string>());
var channelsWithMeta = new List<ChannelWithMeta>();
var allChannelsWithMeta = new List<ChannelWithMeta>();
var filteredDataIndex = 0;
foreach (var channel in test.Channels)
{
if (Path.GetFileName((channel as Test.Module.AnalogInputChannel).FileName) == DataChannelFilename)
{
//
// Tack on the header information for each channel.
//
var filteredChannelData = null != filteredData && filteredData.Count == 1 ? filteredData[0] : null;
headerLines[FtssHeaderLine.Headers].Add(TAB_LIST_SEPARATOR);
headerLines[FtssHeaderLine.TestDate].Add(test.InceptionDate.ToShortDateString());
headerLines[FtssHeaderLine.TestTime].Add(test.InceptionDate.ToLongTimeString());
headerLines[FtssHeaderLine.TestId].Add(id);
headerLines[FtssHeaderLine.TestDescription].Add(test.Description);
headerLines[FtssHeaderLine.LaboratoryName].Add(LaboratoryName);
headerLines[FtssHeaderLine.LaboratoryContactName].Add(LaboratoryContactName);
headerLines[FtssHeaderLine.LaboratoryContactPhone].Add(LaboratoryContactPhone);
headerLines[FtssHeaderLine.LaboratoryContactEmail].Add(LaboratoryContactEmail);
headerLines[FtssHeaderLine.TestEngineerName].Add(TestEngineerName);
headerLines[FtssHeaderLine.TestEngineerPhone].Add(TestEngineerPhone);
headerLines[FtssHeaderLine.TestEngineerEmail].Add(TestEngineerEmail);
headerLines[FtssHeaderLine.SampleRate].Add(channel.ParentModule.SampleRateHz.ToString("F0"));
headerLines[FtssHeaderLine.HardwareAntiAliasFilter].Add(channel.ParentModule.AaFilterRateHz.ToString("F0"));
headerLines[FtssHeaderLine.DataChannelName].Add(DataChannelFilename);
//13157 Software filter class (SAE Class) incorrect in TSV filtered export.
//if we are filtering AND we have use isocode filter mapping on, then adjust the isocode to match
var isocode = channel is IIsoCodeAware ? (channel as IIsoCodeAware).IsoCode : "";
var swFilter = Filtered && filteredChannelData != null ? filteredChannelData.FilterDescription : "NONE";
if (UseISOCodeFilterMapping)
{
var iso = new Common.ISO.IsoCode(isocode);
iso.FilterClass = CFCFilterDTSFileStringConverter.GetIsoCodeFromString(swFilter, UseZeroForUnfiltered);
isocode = iso.StringRepresentation;
}
headerLines[FtssHeaderLine.IsoCode].Add(isocode);
headerLines[FtssHeaderLine.ChannelDescription].Add(channel.ChannelDescriptionString);
headerLines[FtssHeaderLine.ChannelLocation].Add(channel.ChannelName2);
headerLines[FtssHeaderLine.SensorSerialNumber].Add(channel is ISerialNumberAware ? (channel as ISerialNumberAware).SerialNumber : "");
headerLines[FtssHeaderLine.SoftwareFilter].Add(swFilter);
headerLines[FtssHeaderLine.SoftwareFilterDb].Add(Filtered && filteredChannelData != null ? filteredChannelData.FilterFrequencyHz.ToString("F0") : "NONE");
headerLines[FtssHeaderLine.EngineeringUnits].Add(channel is IEngineeringUnitAware ? (channel as IEngineeringUnitAware).EngineeringUnits.TrimEnd() : "");
headerLines[FtssHeaderLine.UserComment].Add("");
var preTriggerSamples = channel.ParentModule.TriggerSampleNumbers[0] - (double)channel.ParentModule.StartRecordSampleNumber;
if (preTriggerSamples < 0) { preTriggerSamples = 0D; }
if (preTriggerSamples > channel.ParentModule.NumberOfSamples) { preTriggerSamples = channel.ParentModule.NumberOfSamples; }
if (preTriggerSamples > Start * sampleRate) { preTriggerSamples = Math.Truncate(Start * sampleRate); }
headerLines[FtssHeaderLine.PreZero].Add((preTriggerSamples / SubSampleInterval).ToString());
var postTriggerSamples = channel.ParentModule.NumberOfSamples - preTriggerSamples;
if (postTriggerSamples < 0) { postTriggerSamples = 0D; }
if (postTriggerSamples > Stop * sampleRate) { postTriggerSamples = Math.Truncate(Stop * sampleRate); }
headerLines[FtssHeaderLine.PostZero].Add((postTriggerSamples / SubSampleInterval).ToString());
headerLines[FtssHeaderLine.DataZero].Add(channel.DataZeroLevelAdc.ToString());
var scaler = new DataScaler();
scaler.IsInverted = channel is IInversionAware ? (channel as IInversionAware).IsInverted : false;
if ((channel as ILinearized).LinearizationFormula.IsValid())
{
scaler.SetLinearizationFormula((channel as ILinearized).LinearizationFormula);
}
else
{
scaler.SetLinearizationFormula(null);
}
scaler.Digital = (channel as Test.Module.AnalogInputChannel).IsDigital();
scaler.SetDigitalMultiplier((channel as Test.Module.AnalogInputChannel).DigitalMultiplier);
scaler.DigitalMode = (channel as Test.Module.AnalogInputChannel).DigitalMode;
scaler.SetScaleFactorMv(channel.Data.ScaleFactorMv);
scaler.SetScaleFactorEU(channel.Data.ScaleFactorEU);
scaler.SetUseEUScaleFactors(channel.Data.UseEUScaleFactors);
scaler.UnitConversion = (channel as Test.Module.AnalogInputChannel).UnitConversion;
scaler.BasedOnOutputAtCapacity = (channel as Test.Module.AnalogInputChannel).AtCapacity;
scaler.CapacityOutputIsBasedOn = (channel as Test.Module.AnalogInputChannel).CapacityOutputIsBasedOn;
scaler.SensitivityUnits = (channel as Test.Module.AnalogInputChannel).SensitivityUnits;
scaler.Multiplier = (channel as Test.Module.AnalogInputChannel).Multiplier;
if (channel is Test.Module.AnalogInputChannel)
{
scaler.IEPE = (channel as Test.Module.AnalogInputChannel).Bridge == SensorConstants.BridgeType.IEPE;
scaler.Digital = (channel as Test.Module.AnalogInputChannel).Bridge == SensorConstants.BridgeType.DigitalInput;
}
scaler.SetMvPerEu(channel.Data.MvPerEu);
scaler.SetDataZeroLevelADC(channel.DataZeroLevelAdc);
scaler.SetRemovedADC(channel.RemovedADC);
scaler.SetRemovedInternalADC(channel.RemovedInternalADC);
scaler.SetZeroMvInADC(channel.ZeroMvInADC);
try { scaler.SetWindowAverageADC(channel.WindowAverageADC); }
catch (System.Exception) { }
if (channel is Test.Module.AnalogInputChannel)
{ //
// Maybe these should be replaced by DTS.DAS.Concepts versions for casting? Would need to
// add excitation voltage as a concept, and proportional to excitation.
//
var analogChannel = channel as Test.Module.AnalogInputChannel;
scaler.SetInitialOffset(analogChannel.InitialOffset);
scaler.ZeroMethodType = analogChannel.ZeroMethod;
scaler.NominalExcitationVoltage = analogChannel.ExcitationVoltage;
if (analogChannel.MeasuredExcitationVoltageValid)
{
try { scaler.MeasuredExcitationVoltage = analogChannel.MeasuredExcitationVoltage; }
catch { };
}
if (analogChannel.FactoryExcitationVoltageValid)
{
try { scaler.FactoryExcitationVoltage = analogChannel.FactoryExcitationVoltage; }
catch { };
}
scaler.ProportionalToExcitation = analogChannel.ProportionalToExcitation;
}
var dStartTime = channel.ParentModule.StartRecordSampleNumber / (double)channel.ParentModule.SampleRateHz;
if (channel.ParentModule.TriggerSampleNumbers.Count > 0)
{
dStartTime -= channel.ParentModule.TriggerSampleNumbers[0] / (double)channel.ParentModule.SampleRateHz;
}
channelsWithMeta.Add(
new ChannelWithMeta(
channel,
scaler,
channel.ParentModule.SampleRateHz,
dStartTime
)
);
headerLines[FtssHeaderLine.ScaleEu].Add(scaler.GetAdcToEuScalingFactor().ToString());
headerLines[FtssHeaderLine.ScaleMv].Add(scaler.GetAdcToMvScalingFactor().ToString());
headerLines[FtssHeaderLine.DataStart].Add(TAB_LIST_SEPARATOR);
headerLines[FtssHeaderLine.Labels].Add(channel.ChannelDescriptionString);
break;
}
}
//FB14621: Recalculate minStartTime and dataCollectionLength here after pulling out channelsWithMeta,
// rather than in Export which is doing the whole test/ROI
minStartTime = ChannelWithMeta.GetMinStartTime(Start, channelsWithMeta);
var minStopTime = ChannelWithMeta.GetMinStopTime(Stop, channelsWithMeta);
dataCollectionLength = (int)((minStopTime - minStartTime) * sampleRate);
VerifyExportedFileWillFitOnDisk(test.Id,
targetPath.Remove(targetPath.IndexOf(Path.VolumeSeparatorChar) + 1),
headerLines,
coder,
channelsWithMeta,
dataCollectionLength,
minStartTime,
sampleRate,
cancelRequested);
// Apply filtering to channel data at this point?
// Thinking maybe since all the cool filter utilities are up in the Slice Control layer, it
// may just be a better idea to create some filtered test at that level using the event channels
// and then just add some code here that gracefully handles Data-data instead of PersistentChannelInfo
// data...?
//Dictionary<ChannelWithMeta, double[ ]> filteredData = new Dictionary<ChannelWithMeta, double[ ]>( );
//SaeJ211.FilterUtility filterUtility = new SaeJ211.FilterUtility( );
//foreach ( ChannelWithMeta channelWithMeta in channelsWithMeta )
//{
// this.CurrentFilter = Slice.Control.Event.Module.Channel.DefaultSaeJ211Filter.Parse( thatAnalogChannel.SoftwareFilter );
// filterUtility.SampleRate = channelWithMeta.SampleRate;
// filterUtility.Cfc = ( channelWithMeta.Channel as Test.Module.AnalogInputChannel ).SoftwareFilter;
//}
foreach (FtssHeaderLine ftssHeaderLine in Enum.GetValues(typeof(FtssHeaderLine)))
{ //
// Write out the assembled header information to the specified filestream.
//
if (headerLines.Keys.Contains(ftssHeaderLine))
{
var channelValues = headerLines[ftssHeaderLine];
fileWriter.Write(coder.DecodeAttributeValue(ftssHeaderLine) + TAB_LIST_SEPARATOR);
foreach (var channelValue in channelValues)
fileWriter.Write(channelValue + TAB_LIST_SEPARATOR);
fileWriter.WriteLine();
}
}
for (var i = 0; i <= dataCollectionLength; i++)
{
if (null != cancelRequested && cancelRequested()) { break; }
fileWriter.Write(string.Format("{0}{1}", (minStartTime + i * 1.0 / sampleRate).ToString(NUMBER_FORMAT), TAB_LIST_SEPARATOR));
var bNeedComma = false;
foreach (var channelWithMeta in channelsWithMeta)
{
if (bNeedComma) { fileWriter.Write(TAB_LIST_SEPARATOR); }
else { bNeedComma = true; }
//
// If this channel's data is valid at the current time/index then go ahead and send it out
// to the file; otherwise write out a blank space.
//
var thisChannelsIndexAtCurrentTime = i - (int)((channelWithMeta.StartTime - minStartTime) * channelWithMeta.SampleRate);
if (Filtered)
{
if (filteredDataIndex < filteredData.Count)
{
if (thisChannelsIndexAtCurrentTime >= 0 && thisChannelsIndexAtCurrentTime < filteredData[filteredDataIndex].Data.Length)
{
fileWriter.Write(filteredData[filteredDataIndex].Data[thisChannelsIndexAtCurrentTime].ToString(NUMBER_FORMAT));
}
}
else
{
fileWriter.Write(double.NaN.ToString());
}
}
else
{
double dInitialEU = 0;
var aChannel = channelWithMeta.Channel as Test.Module.AnalogInputChannel;
if (null != aChannel) { dInitialEU = aChannel.InitialEu; }
if (thisChannelsIndexAtCurrentTime >= 0 && (ulong)thisChannelsIndexAtCurrentTime < aChannel.ParentModule.NumberOfSamples)
{
fileWriter.Write(channelWithMeta.Scaler.GetEU(channelWithMeta.Channel.PersistentChannelInfo[thisChannelsIndexAtCurrentTime]).ToString(NUMBER_FORMAT));
}
}
filteredDataIndex++;
}
if (0 == i % DataSamplesPerTick)
{
OnTick?.Invoke(this, (double)totalWriteTicksDispatched++ / totalWriteTicksNeeded * 100);
System.Windows.Forms.Application.DoEvents();
}
fileWriter.WriteLine();
filteredDataIndex = 0;
}
fileWriter.Flush();
}
catch (System.Exception ex)
{
throw new Exception("encountered problem writing FTSS/Excel channel headers", ex);
}
}
public double Start { get; set; } = 0D;
public double Stop { get; set; } = 0D;
public ushort SubSampleInterval { get; set; }
public bool Filtered { get; set; }
}
}
}