2767 lines
93 KiB
C#
2767 lines
93 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using DTS.Common.Classes.Sensors;
|
|
using DTS.Common.Enums;
|
|
using DTS.Common.Enums.Sensors;
|
|
using DTS.Common.Utilities;
|
|
using DTS.Common.Utilities.Logging;
|
|
|
|
namespace DTS.Serialization.TDAS
|
|
{
|
|
/// <summary>
|
|
/// this is a class for helping to read and write the TLF
|
|
/// there are a lot of classes for the sections in the tlf, but most of them are very similar
|
|
/// and it would be pretty easy to combine them into a generic class, but I'll leave that
|
|
/// till things are up and running first
|
|
/// </summary>
|
|
public class TLF
|
|
{
|
|
public const int MODULE_TYPE_NONE = 0;
|
|
public const int MODULE_TYPE_SIM = 1;
|
|
public const int MODULE_TYPE_TOM = 2;
|
|
public const int MODULE_TYPE_DIM = 3;
|
|
|
|
public const int CHANNEL_TYPE_NONE = 0;
|
|
public const int CHANNEL_TYPE_AIN = 1;
|
|
public const int CHANNEL_TYPE_DIGITAL_IN = 2;
|
|
public const int CHANNEL_TYPE_SQUIB = 3;
|
|
public const int CHANNEL_TYPE_DIGITAL_OUT = 4;
|
|
public const int CHANNEL_TYPE_SQUIB_VOLTAGE = 5;
|
|
public const int CHANNEL_TYPE_SQUIB_CURRENT = 6;
|
|
|
|
public const int MAX_RACKSN = 6;
|
|
|
|
/// <summary>
|
|
/// per Jim Platte, GM RDF requires only 2 digits for module serial
|
|
/// </summary>
|
|
/// <param name="serialNumber"></param>
|
|
/// <returns></returns>
|
|
public static string GetModuleSerialNumber(string serialNumber)
|
|
{
|
|
return $"{serialNumber.Substring(0, 2)}{serialNumber.Substring(serialNumber.Length - 4)}";
|
|
}
|
|
|
|
private static bool IsDIM(string serialNumber)
|
|
{
|
|
return serialNumber.StartsWith("SPD") || serialNumber.StartsWith("SLD");
|
|
}
|
|
|
|
/// <summary>
|
|
/// parses out "racks/modules/channels" in a way familiar to tdas control
|
|
/// tdas control makes some assumptions in the number of mods/rack and channels per mod
|
|
/// basically we have to treat each bridge as a module and each base as a rack to
|
|
/// this function just parses out the bases and the bridges as racks and modules
|
|
/// </summary>
|
|
/// <param name="test"></param>
|
|
/// <param name="rackToIndex"></param>
|
|
/// <param name="moduleSerialNumberToRackIndex"></param>
|
|
/// <returns></returns>
|
|
private Rack[] GetRacks(Test test, out Dictionary<string, int> moduleSerialNumberToRackIndex)
|
|
{
|
|
var racks = new List<Rack>();
|
|
var rackToIndex = new Dictionary<string, int>();
|
|
moduleSerialNumberToRackIndex = new Dictionary<string, int>();
|
|
foreach (var module in test.Modules)
|
|
{
|
|
var rackSerialNumber = module.BaseSerialNumber ?? module.SerialNumber;
|
|
if (!rackToIndex.ContainsKey(rackSerialNumber))
|
|
{
|
|
rackToIndex.Add(rackSerialNumber, racks.Count);
|
|
racks.Add(new Rack(rackSerialNumber));
|
|
}
|
|
var rackIndex = rackToIndex[rackSerialNumber];
|
|
racks[rackIndex].Modules[module.Number] = module.SerialNumber;
|
|
moduleSerialNumberToRackIndex[module.SerialNumber] = rackIndex;
|
|
}
|
|
return racks.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// this class is for simplifying the rack/module/channel relationship between slice and tdas control
|
|
/// for the purpose of serializing
|
|
/// </summary>
|
|
internal class Rack
|
|
{
|
|
public string SerialNumber { get; set; }
|
|
public string[] Modules { get; set; }
|
|
public int RackIndex { get; set; }
|
|
|
|
public Rack(string serialNumber)
|
|
{
|
|
SerialNumber = serialNumber;
|
|
Modules = new string[8];
|
|
for (var i = 0; i < 8; i++)
|
|
{
|
|
Modules[i] = "-1";
|
|
}
|
|
}
|
|
}
|
|
|
|
public string SoftwareVersion { get; set; } = "7.1.2t";
|
|
|
|
public string TSFFile { get; set; } = "";
|
|
|
|
public DateTime TestTime { get; set; } = DateTime.MinValue;
|
|
|
|
public string TestDescription { get; set; } = null;
|
|
|
|
private readonly List<TLFSection> _sections = new List<TLFSection>();
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.WriteLine(SoftwareVersion);
|
|
sw.WriteLine(TSFFile);
|
|
sw.WriteLine($"{TestTime.Month:00}-{TestTime.Day:00}-{TestTime.Year:00}");
|
|
sw.WriteLine(TestTime.ToString("HH:mm:ss"));
|
|
sw.WriteLine(TestDescription);
|
|
foreach (var section in _sections)
|
|
{
|
|
section.Serialize(sw);
|
|
}
|
|
}
|
|
|
|
private readonly Rack[] _racks;
|
|
private readonly Dictionary<string, int> _moduleSerialNumberToRackIndex;
|
|
|
|
public static System.Globalization.CultureInfo InvariantCulture = new System.Globalization.CultureInfo("");
|
|
|
|
public TLF(string file, Test test, string id)
|
|
{
|
|
Initialize();
|
|
TSFFile = test.Id + "/" + id;
|
|
if (TestTime == DateTime.MinValue)
|
|
{
|
|
TestTime = test.InceptionDate;
|
|
}
|
|
//if (TestTime.Date != test.InceptionDate.Date) { throw new NotSupportedException("Tests are on different days"); }
|
|
//preserve the test description unless null or blank
|
|
if (string.IsNullOrEmpty(TestDescription))
|
|
{
|
|
TestDescription = test.Description;
|
|
}
|
|
SamplingSection.AddTestData(test);
|
|
|
|
_racks = GetRacks(test, out _moduleSerialNumberToRackIndex);
|
|
RackSection.AddTestData(test, _racks);
|
|
ModuleSection.AddTestData(test, _racks);
|
|
SensorChannelSection.AddTestData(test, _racks, _moduleSerialNumberToRackIndex);
|
|
var lastChannel = SensorChannelSection.LastChannel;
|
|
CalculatedChannelSection.AddTestData();
|
|
TOMSection.AddTestData(test, _racks, _moduleSerialNumberToRackIndex);
|
|
lastChannel = SensorChannelSection.LastChannel;
|
|
DIMSection.AddTestData(test, _racks, _moduleSerialNumberToRackIndex, lastChannel);
|
|
lastChannel = DIMSection.LastChannel;
|
|
G5DigitalChannelSection.AddTestData(test, _racks, _moduleSerialNumberToRackIndex, lastChannel);
|
|
}
|
|
|
|
private void BackupFiles(string file)
|
|
{
|
|
try
|
|
{
|
|
var fi = new System.IO.FileInfo(file);
|
|
var backupDirectory = System.IO.Path.Combine(fi.Directory.FullName, "PreMerge");
|
|
if (!System.IO.Directory.Exists(backupDirectory))
|
|
{
|
|
System.IO.Directory.CreateDirectory(backupDirectory);
|
|
}
|
|
|
|
var binFiles = fi.Directory.GetFiles("*.BIN");
|
|
foreach (var binFile in binFiles)
|
|
{
|
|
CopyFile(binFile.FullName, System.IO.Path.Combine(backupDirectory, binFile.Name));
|
|
}
|
|
|
|
CopyFile(file, System.IO.Path.Combine(backupDirectory, fi.Name));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log("Problem backing up files", file, ex);
|
|
}
|
|
}
|
|
|
|
private void CopyFile(string source, string directory)
|
|
{
|
|
try
|
|
{
|
|
System.IO.File.Copy(source, directory);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log("Problem copying file", source, directory, ex);
|
|
}
|
|
}
|
|
|
|
private SamplingSection SamplingSection => _sections[0] as SamplingSection;
|
|
|
|
private RackSection RackSection => _sections[1] as RackSection;
|
|
|
|
private ModuleSection ModuleSection => _sections[2] as ModuleSection;
|
|
|
|
private SensorChannelSection SensorChannelSection => _sections[3] as SensorChannelSection;
|
|
|
|
private CalculatedChannelSection CalculatedChannelSection => _sections[4] as CalculatedChannelSection;
|
|
|
|
private TOMSection TOMSection => _sections[5] as TOMSection;
|
|
|
|
private DIMSection DIMSection => _sections[6] as DIMSection;
|
|
|
|
private G5DigitalChannelsSection G5DigitalChannelSection => _sections[7] as G5DigitalChannelsSection;
|
|
|
|
private void LoadFile(string file)
|
|
{
|
|
using (var sw = new System.IO.StreamReader(file))
|
|
{
|
|
SoftwareVersion = sw.ReadLine();
|
|
TSFFile = sw.ReadLine();
|
|
var dtTestDate = DateTime.Parse(sw.ReadLine());
|
|
var ts = TimeSpan.Parse(sw.ReadLine());
|
|
dtTestDate = dtTestDate.Add(ts);
|
|
TestTime = dtTestDate;
|
|
TestDescription = sw.ReadLine();
|
|
SamplingSection.ReadTestData(sw);
|
|
RackSection.ReadTestData(sw);
|
|
ModuleSection.ReadTestData(sw);
|
|
SensorChannelSection.ReadTestData(sw);
|
|
CalculatedChannelSection.ReadTestData(sw);
|
|
TOMSection.ReadTestData(sw);
|
|
DIMSection.ReadTestData(sw);
|
|
G5DigitalChannelSection.ReadTestData(sw);
|
|
ExistingChannels = SensorChannelSection.ExistingChannels;
|
|
LastChannelNumber = Math.Max(SensorChannelSection.LastChannel, DIMSection.LastChannel);
|
|
LastChannelNumber = Math.Max(LastChannelNumber, G5DigitalChannelSection.LastChannel);
|
|
SensorChannelSection.StartingSLICEChannel = LastChannelNumber;
|
|
}
|
|
}
|
|
|
|
private void Initialize()
|
|
{
|
|
_sections.Add(new SamplingSection());
|
|
_sections.Add(new RackSection());
|
|
_sections.Add(new ModuleSection());
|
|
_sections.Add(new SensorChannelSection());
|
|
_sections.Add(new CalculatedChannelSection());
|
|
_sections.Add(new TOMSection());
|
|
_sections.Add(new DIMSection());
|
|
_sections.Add(new G5DigitalChannelsSection());
|
|
}
|
|
|
|
public int ExistingChannels { get; set; } = 0;
|
|
|
|
public int LastChannelNumber { get; set; } = 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// we could make sections really generic and just be composed of strings
|
|
/// and so on, but for now lets just add the Serialize method
|
|
/// Serialize serializes the section to the underlying stream
|
|
/// </summary>
|
|
internal interface TLFSection
|
|
{
|
|
void Serialize(System.IO.StreamWriter sw);
|
|
}
|
|
|
|
internal class SamplingSection : TLFSection
|
|
{
|
|
private SamplingInformationLine _samplingInformation = null;
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.WriteLine("---- Start Sampling Information ----");
|
|
sw.WriteLine(
|
|
"rate(Hz),pretrigtime(sec),posttrigtime(sec),AdjAAfilter(Hz),postcaltime(sec),prezerodatapts,postzerodatapts,originalt=0pt");
|
|
if (null != _samplingInformation)
|
|
{
|
|
_samplingInformation.Serialize(sw);
|
|
}
|
|
sw.WriteLine("---- End Sampling Information ----");
|
|
}
|
|
|
|
public void AddTestData(Test test)
|
|
{
|
|
if (null == _samplingInformation)
|
|
{
|
|
_samplingInformation = new SamplingInformationLine();
|
|
_samplingInformation.AdjAAFilter = test.Modules[0].AaFilterRateHz;
|
|
_samplingInformation.OriginalTimeZeroPoint =
|
|
Convert.ToInt32(test.Modules[0].TriggerSampleNumbers[0] -
|
|
(double)test.Modules[0].StartRecordSampleNumber);
|
|
_samplingInformation.PostCalTime = 0D;
|
|
|
|
//rate(hz)
|
|
_samplingInformation.SamplingRate = test.Modules[0].SampleRateHz;
|
|
|
|
int actualPostZeroDataPoints;
|
|
if (test.Modules[0].StartRecordSampleNumber > test.Modules[0].TriggerSampleNumbers[0])
|
|
{
|
|
// The test must have specified a positive (post-zero) value for pre-trigger seconds
|
|
_samplingInformation.PreTriggerSeconds = test.Modules[0].RequestedPreTriggerSeconds;
|
|
_samplingInformation.PreZeroDataPoints = 0;
|
|
actualPostZeroDataPoints = Convert.ToInt32((double)test.Modules[0].NumberOfSamples);
|
|
}
|
|
else
|
|
{
|
|
//pretrigtime(sec)
|
|
_samplingInformation.PreTriggerSeconds =
|
|
Math.Abs(test.Modules[0].RequestedPreTriggerSeconds) *
|
|
-1; //Set it to this whether or not it's ROI or All
|
|
|
|
//prezerodatapts
|
|
var requestedPreZeroDataPoints =
|
|
Convert.ToInt32(test.Modules[0].SampleRateHz *
|
|
Math.Abs(test.Modules[0].RequestedPreTriggerSeconds));
|
|
var actualPreZeroDataPoints =
|
|
Convert.ToInt32(test.Modules[0].TriggerSampleNumbers[0] -
|
|
test.Modules[0].StartRecordSampleNumber);
|
|
_samplingInformation.PreZeroDataPoints =
|
|
Math.Min(requestedPreZeroDataPoints, actualPreZeroDataPoints);
|
|
|
|
//postzerodatapts
|
|
actualPostZeroDataPoints = Convert.ToInt32(test.Modules[0].NumberOfSamples -
|
|
(test.Modules[0].TriggerSampleNumbers[0] -
|
|
(double)test.Modules[0].StartRecordSampleNumber));
|
|
}
|
|
//posttrigtime(sec)
|
|
_samplingInformation.PostTriggerSeconds =
|
|
test.Modules[0].RequestedPostTriggerSeconds; //Set it to this whether or not it's ROI or All
|
|
|
|
var requestedPostZeroDataPoints =
|
|
Convert.ToInt32(test.Modules[0].SampleRateHz *
|
|
test.Modules[0].RequestedPostTriggerSeconds) + 1;
|
|
_samplingInformation.PostZeroDataPoints =
|
|
Math.Min(requestedPostZeroDataPoints, actualPostZeroDataPoints);
|
|
}
|
|
}
|
|
|
|
public void ReadTestData(System.IO.StreamReader sr)
|
|
{
|
|
sr.ReadLine(); //--start sampling info
|
|
sr.ReadLine(); //parameters
|
|
if (sr.Peek() != '-')
|
|
{
|
|
_samplingInformation = new SamplingInformationLine(sr.ReadLine());
|
|
}
|
|
sr.ReadLine(); //end sampling info
|
|
}
|
|
}
|
|
|
|
internal class SamplingInformationLine
|
|
{
|
|
public double SamplingRate { get; set; } = 0D;
|
|
|
|
public double PreTriggerSeconds { get; set; } = 0D;
|
|
|
|
public double PostTriggerSeconds { get; set; } = 0D;
|
|
|
|
public double AdjAAFilter { get; set; } = 0D;
|
|
|
|
public double PostCalTime { get; set; } = 0D;
|
|
|
|
public int PreZeroDataPoints { get; set; } = 0;
|
|
|
|
public int PostZeroDataPoints { get; set; } = 0;
|
|
|
|
public int OriginalTimeZeroPoint { get; set; } = 0;
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.Write(SamplingRate.ToString("F1"));
|
|
sw.Write(",");
|
|
sw.Write(PreTriggerSeconds.ToString("F2"));
|
|
sw.Write(",");
|
|
sw.Write(PostTriggerSeconds.ToString("F2"));
|
|
sw.Write(",");
|
|
sw.Write(AdjAAFilter);
|
|
sw.Write(",");
|
|
sw.Write(PostCalTime.ToString("F1"));
|
|
sw.Write(",");
|
|
sw.Write(PreZeroDataPoints);
|
|
sw.Write(",");
|
|
sw.Write(PostZeroDataPoints);
|
|
//sw.Write(",");
|
|
//sw.Write(OriginalTimeZeroPoint); //Don't write this because TDC doesn't unless T0 has been adjusted
|
|
sw.Write(sw.NewLine);
|
|
}
|
|
|
|
public SamplingInformationLine()
|
|
{
|
|
}
|
|
|
|
public SamplingInformationLine(string data)
|
|
{
|
|
var tokens = data.Split(',');
|
|
for (var i = 0; i < tokens.Length; i++)
|
|
{
|
|
var dTemp = double.NegativeInfinity;
|
|
var iTemp = int.MinValue;
|
|
double.TryParse(tokens[i], System.Globalization.NumberStyles.Float, TLF.InvariantCulture, out dTemp);
|
|
int.TryParse(tokens[i], out iTemp);
|
|
|
|
switch (i)
|
|
{
|
|
case 0:
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
SamplingRate = dTemp;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
PreTriggerSeconds = dTemp;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
PostTriggerSeconds = dTemp;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
AdjAAFilter = dTemp;
|
|
}
|
|
break;
|
|
case 4:
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
PostCalTime = dTemp;
|
|
}
|
|
break;
|
|
case 5:
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
PreZeroDataPoints = iTemp;
|
|
}
|
|
break;
|
|
case 6:
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
PostZeroDataPoints = iTemp;
|
|
}
|
|
break;
|
|
case 7:
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
OriginalTimeZeroPoint = iTemp;
|
|
}
|
|
break;
|
|
case 8:
|
|
throw new NotSupportedException("Sampling information has more fields than expected: " + data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class RackSection : TLFSection
|
|
{
|
|
private readonly List<RackInfoLine> _lines = new List<RackInfoLine>();
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.WriteLine("---- Start Rack Information ----");
|
|
sw.WriteLine("Rack,racksn,mod1sn,mod2sn,mod3sn,mod4sn,mod5sn,mod6sn,mod7sn,mod8sn");
|
|
if (null != _lines)
|
|
{
|
|
foreach (var line in _lines)
|
|
{
|
|
line.Serialize(sw);
|
|
}
|
|
}
|
|
sw.WriteLine("---- End Rack Information ----");
|
|
}
|
|
|
|
public void AddTestData(Test test, TLF.Rack[] racks)
|
|
{
|
|
for (var i = 0; i < racks.Length; i++)
|
|
{
|
|
var rack = racks[i];
|
|
var ril = new RackInfoLine(rack);
|
|
foreach (var existingRIL in _lines)
|
|
{
|
|
if (existingRIL.RackSerialNumber == ril.RackSerialNumber)
|
|
{
|
|
throw new NotSupportedException(
|
|
"TDAS::RackSection::AddTestData already exists in TLF, a second export is not supported");
|
|
}
|
|
}
|
|
ril.Rack = GetMaxRackIndex() + 1;
|
|
_maxRack = ril.Rack;
|
|
_lines.Add(ril);
|
|
rack.RackIndex = ril.Rack;
|
|
}
|
|
}
|
|
|
|
private int _maxRack = -1;
|
|
|
|
private int GetMaxRackIndex()
|
|
{
|
|
//we have to calculate it if there is data already in a tlf, for all the rest we add ourselves
|
|
//we can just update our internal count
|
|
//we have to count max rack since the TLF rack index could be anything and is probably not just
|
|
//"1" or so on
|
|
if (-1 == _maxRack)
|
|
{
|
|
_maxRack = 0;
|
|
for (var i = 0; i < _lines.Count; i++)
|
|
{
|
|
if (_lines[i].Rack > _maxRack)
|
|
{
|
|
_maxRack = _lines[i].Rack;
|
|
}
|
|
}
|
|
}
|
|
return _maxRack;
|
|
}
|
|
|
|
public void ReadTestData(System.IO.StreamReader sr)
|
|
{
|
|
sr.ReadLine(); //start rackinfo
|
|
sr.ReadLine(); //rack parameters
|
|
while (sr.Peek() != '-')
|
|
{
|
|
_lines.Add(new RackInfoLine(sr.ReadLine()));
|
|
}
|
|
sr.ReadLine(); //end rack info
|
|
}
|
|
}
|
|
|
|
internal class RackInfoLine
|
|
{
|
|
public int Rack { get; set; }
|
|
|
|
public string RackSerialNumber { get; set; }
|
|
|
|
private List<string> _modSerialNumbers;
|
|
|
|
public string[] ModSerialNumbers
|
|
{
|
|
get => _modSerialNumbers.ToArray();
|
|
set => _modSerialNumbers = new List<string>(value);
|
|
}
|
|
|
|
public RackInfoLine()
|
|
{
|
|
_modSerialNumbers = new List<string>() { "0", "0", "0", "0", "0", "0", "0", "0" };
|
|
}
|
|
|
|
public RackInfoLine(string data)
|
|
{
|
|
_modSerialNumbers = new List<string>() { "0", "0", "0", "0", "0", "0", "0", "0" };
|
|
var tokens = data.Split(',');
|
|
for (var i = 0; i < tokens.Length; i++)
|
|
{
|
|
if (0 == i)
|
|
{
|
|
Rack = int.Parse(tokens[i]);
|
|
}
|
|
else if (1 == i)
|
|
{
|
|
RackSerialNumber = tokens[i];
|
|
}
|
|
else if (i < 10)
|
|
{
|
|
_modSerialNumbers[i - 2] = tokens[i];
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException("Invalid number of parameters in rack info line: " + data);
|
|
}
|
|
}
|
|
}
|
|
|
|
public RackInfoLine(TLF.Rack rack)
|
|
{
|
|
RackSerialNumber = rack.SerialNumber;
|
|
_modSerialNumbers = new List<string>(rack.Modules);
|
|
}
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.Write(Rack);
|
|
sw.Write(",");
|
|
|
|
////restrict to 7 characters for TDC
|
|
//sw.Write(RackSerialNumber.Length > TLF.MAX_RACKSN ? TLF.GetModuleSerialNumber(RackSerialNumber) : RackSerialNumber);
|
|
sw.Write(RackSerialNumber);
|
|
|
|
foreach (var s in _modSerialNumbers)
|
|
{
|
|
sw.Write(",");
|
|
sw.Write(s);
|
|
}
|
|
sw.Write(sw.NewLine);
|
|
}
|
|
}
|
|
|
|
internal class ModuleSection : TLFSection
|
|
{
|
|
private readonly List<ModuleInfoLine> _lines = new List<ModuleInfoLine>();
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.WriteLine("---- Start Module Information ----");
|
|
sw.WriteLine("rack,module,trigmode,trigchan,trigdir,triglevel,moduletype,prediag,postdiag");
|
|
if (null != _lines)
|
|
{
|
|
foreach (var line in _lines)
|
|
{
|
|
line.Serialize(sw);
|
|
}
|
|
}
|
|
sw.WriteLine("---- End Module Information ----");
|
|
}
|
|
|
|
//@TODO - fix difference between tdas and slice
|
|
//now things get a _little_ complicated
|
|
//slice can have multiple trigger directions and channels
|
|
//tdascontrol will only allow one trigger channel and one direction per channel
|
|
//lets resolve this later and omit the trigger direction and level now
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="test"></param>
|
|
/// <param name="racks"></param>
|
|
/// <param name="moduleSNToRackIdx"></param>
|
|
public void AddTestData(Test test, TLF.Rack[] racks)
|
|
{
|
|
for (var i = 0; i < racks.Length; i++)
|
|
{
|
|
var rack = racks[i];
|
|
for (var iModule = 0; iModule < rack.Modules.Length; iModule++)
|
|
{
|
|
if ("-1" == rack.Modules[iModule])
|
|
{
|
|
continue;
|
|
}
|
|
var rackIndex = rack.RackIndex;
|
|
var moduleIndex = iModule + 1;
|
|
var moduleType = 0;
|
|
if (IsSIM(rack.Modules[iModule]))
|
|
{
|
|
moduleType = TLF.MODULE_TYPE_SIM;
|
|
}
|
|
else if (IsTOM(rack.Modules[iModule]))
|
|
{
|
|
moduleType = TLF.MODULE_TYPE_TOM;
|
|
}
|
|
_lines.Add(new ModuleInfoLine(rackIndex, moduleIndex, moduleType));
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool IsSIM(string serialNumber)
|
|
{
|
|
return serialNumber.StartsWith("DM") || serialNumber.StartsWith("LM");
|
|
}
|
|
|
|
private bool IsTOM(string serialNumber)
|
|
{
|
|
return serialNumber.StartsWith("TOM");
|
|
}
|
|
|
|
public void ReadTestData(System.IO.StreamReader sr)
|
|
{
|
|
sr.ReadLine(); //StartModuleInfo;
|
|
sr.ReadLine(); //parametersheader
|
|
while (sr.Peek() != '-')
|
|
{
|
|
_lines.Add(new ModuleInfoLine(sr.ReadLine()));
|
|
}
|
|
sr.ReadLine(); //endmoduleinfo
|
|
}
|
|
}
|
|
|
|
internal class ModuleInfoLine
|
|
{
|
|
public int Rack { get; set; }
|
|
|
|
public int Module { get; set; }
|
|
|
|
public int TriggerMode { get; set; }
|
|
|
|
public int TriggerChannel { get; set; }
|
|
|
|
public int TriggerDirection { get; set; }
|
|
|
|
public double TriggerLevel { get; set; }
|
|
|
|
public int ModuleType { get; set; }
|
|
|
|
public string PreDiag { get; set; } = null;
|
|
|
|
public string PostDiag { get; set; } = null;
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.Write(Rack);
|
|
sw.Write(",");
|
|
sw.Write(Module);
|
|
sw.Write(",");
|
|
sw.Write(TriggerMode);
|
|
sw.Write(",");
|
|
sw.Write(TriggerChannel);
|
|
sw.Write(",");
|
|
sw.Write(TriggerDirection);
|
|
sw.Write(",");
|
|
sw.Write(TriggerLevel.ToString("F1"));
|
|
sw.Write(",");
|
|
sw.Write(ModuleType);
|
|
if (null != PreDiag)
|
|
{
|
|
sw.Write(",");
|
|
sw.Write(PreDiag);
|
|
}
|
|
if (null != PostDiag)
|
|
{
|
|
sw.Write(",");
|
|
sw.Write(PostDiag);
|
|
}
|
|
sw.Write(sw.NewLine);
|
|
}
|
|
|
|
public ModuleInfoLine(int rackIdx, int moduleIdx, int moduleType)
|
|
{
|
|
Rack = rackIdx;
|
|
Module = moduleIdx;
|
|
TriggerMode = 0;
|
|
TriggerChannel = 1;
|
|
TriggerDirection = 0;
|
|
TriggerLevel = 0D;
|
|
ModuleType = moduleType;
|
|
PreDiag = null;
|
|
PostDiag = null;
|
|
}
|
|
|
|
public ModuleInfoLine(string data)
|
|
{
|
|
var tokens = data.Split(',');
|
|
for (var i = 0; i < tokens.Length; i++)
|
|
{
|
|
//int iTemp = int.MinValue;
|
|
//double dTemp = double.NegativeInfinity;
|
|
switch (i)
|
|
{
|
|
case 0: //rack
|
|
Rack = int.Parse(tokens[i]);
|
|
break;
|
|
case 1: //module
|
|
Module = int.Parse(tokens[i]);
|
|
break;
|
|
case 2: //trigmode
|
|
TriggerMode = int.Parse(tokens[i]);
|
|
break;
|
|
case 3: //trigchan
|
|
TriggerChannel = int.Parse(tokens[i]);
|
|
break;
|
|
case 4: //trigdir
|
|
TriggerDirection = int.Parse(tokens[i]);
|
|
break;
|
|
case 5: //triglevel
|
|
TriggerLevel = double.Parse(tokens[i]);
|
|
break;
|
|
case 6: //moduletype
|
|
ModuleType = int.Parse(tokens[i]);
|
|
break;
|
|
case 7: //prediag
|
|
PreDiag = tokens[i];
|
|
break;
|
|
case 8: //postdiag
|
|
PostDiag = tokens[i];
|
|
break;
|
|
default:
|
|
throw new NotSupportedException("invalid parameter in module line: " + data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class PreTestDataLine
|
|
{
|
|
public int DataChannel { get; set; }
|
|
|
|
public int Rack { get; set; }
|
|
|
|
public int Module { get; set; }
|
|
|
|
public int Channel { get; set; }
|
|
|
|
public string Description { get; set; }
|
|
|
|
public string SerialNumber { get; set; }
|
|
|
|
public double OffsetLow { get; set; }
|
|
|
|
public double OffsetHigh { get; set; }
|
|
|
|
public CalMode CalMode { get; set; }
|
|
|
|
public double CalStep { get; set; }
|
|
|
|
public double ShuntValueEU { get; set; }
|
|
|
|
public bool ProportionalToExcitation { get; set; }
|
|
|
|
//mv/eu or mv/v/eu
|
|
public double Sensitivity { get; set; }
|
|
|
|
public double Gain { get; set; }
|
|
|
|
public double ExcitationVoltage { get; set; }
|
|
|
|
public string EU { get; set; }
|
|
|
|
public int SoftwareFilter { get; set; }
|
|
|
|
public bool Invert { get; set; }
|
|
|
|
public ZeroRef ZeroRef { get; set; }
|
|
|
|
public double DesiredMaxRange { get; set; }
|
|
|
|
public string CommentField { get; set; }
|
|
|
|
public DateTime CalDate { get; set; }
|
|
|
|
public bool Offset { get; set; }
|
|
|
|
public double InitialEU { get; set; }
|
|
|
|
public string SensorId { get; set; }
|
|
|
|
public string ISOCode { get; set; }
|
|
|
|
public double IRTRACCExponent { get; set; }
|
|
|
|
public int Category { get; set; }
|
|
|
|
private string SanitizeCommas(string s)
|
|
{
|
|
return s.Replace(',', '_');
|
|
}
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.Write(DataChannel);
|
|
sw.Write(",");
|
|
sw.Write(Rack);
|
|
sw.Write(",");
|
|
sw.Write(Module);
|
|
sw.Write(",");
|
|
sw.Write(Channel);
|
|
sw.Write(",");
|
|
sw.Write(SanitizeCommas(Description));
|
|
sw.Write(",");
|
|
sw.Write(SanitizeCommas(SerialNumber));
|
|
sw.Write(",");
|
|
sw.Write(OffsetLow.ToString("F1"));
|
|
sw.Write(",");
|
|
sw.Write(OffsetHigh.ToString("F1"));
|
|
sw.Write(",");
|
|
sw.Write(CalMode.ToString());
|
|
sw.Write(",");
|
|
sw.Write(CalStep.ToString("F1"));
|
|
sw.Write(",");
|
|
sw.Write(ShuntValueEU.ToString("F1"));
|
|
sw.Write(",");
|
|
if (ProportionalToExcitation)
|
|
{
|
|
sw.Write("Y");
|
|
}
|
|
else
|
|
{
|
|
sw.Write("N");
|
|
}
|
|
sw.Write(",");
|
|
sw.Write(Sensitivity.ToString("F12"));
|
|
sw.Write(",");
|
|
sw.Write(Gain.ToString("F5"));
|
|
sw.Write(",");
|
|
sw.Write(ExcitationVoltage.ToString("F5"));
|
|
sw.Write(",");
|
|
sw.Write(SanitizeCommas(EU));
|
|
sw.Write(",");
|
|
sw.Write(SoftwareFilter);
|
|
sw.Write(",");
|
|
if (Invert)
|
|
{
|
|
sw.Write("1");
|
|
}
|
|
else
|
|
{
|
|
sw.Write("0");
|
|
}
|
|
sw.Write(",");
|
|
sw.Write(ZeroRef.ToString());
|
|
sw.Write(",");
|
|
sw.Write(DesiredMaxRange.ToString("F1"));
|
|
sw.Write(",");
|
|
if (string.IsNullOrWhiteSpace(CommentField))
|
|
{
|
|
sw.Write("None");
|
|
}
|
|
else
|
|
{
|
|
sw.Write(SanitizeCommas(CommentField));
|
|
}
|
|
sw.Write(",");
|
|
sw.Write($"{CalDate.Month}_{CalDate.Day}_{CalDate.Year}");
|
|
sw.Write(",");
|
|
if (Offset)
|
|
{
|
|
sw.Write("Y");
|
|
}
|
|
else
|
|
{
|
|
sw.Write("N");
|
|
}
|
|
sw.Write(",");
|
|
sw.Write(InitialEU.ToString("F1"));
|
|
sw.Write(",");
|
|
if (string.IsNullOrWhiteSpace(SensorId))
|
|
{
|
|
sw.Write("0000000000000000");
|
|
}
|
|
else
|
|
{
|
|
sw.Write(SensorId);
|
|
}
|
|
sw.Write(",");
|
|
if (!string.IsNullOrWhiteSpace(ISOCode))
|
|
{
|
|
sw.Write(SanitizeCommas(ISOCode));
|
|
}
|
|
sw.Write(",");
|
|
sw.Write(IRTRACCExponent.ToString("F1"));
|
|
sw.Write(",");
|
|
sw.Write(Category);
|
|
sw.Write(sw.NewLine);
|
|
}
|
|
|
|
private double GetFilter(Test.Module.AnalogInputChannel aic)
|
|
{
|
|
double frequency = 0;
|
|
try
|
|
{
|
|
if (!string.IsNullOrEmpty(aic?.SoftwareFilter))
|
|
{
|
|
if (aic.SoftwareFilter.Contains("Hz"))
|
|
{
|
|
if (double.TryParse(aic.SoftwareFilter.Replace("Hz", ""), out frequency))
|
|
{
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var coder = new DescriptionAttributeCoder<ChannelFilter>();
|
|
foreach (ChannelFilter filterType in Enum.GetValues(typeof(ChannelFilter)))
|
|
{
|
|
if (coder.DecodeAttributeValue(filterType)
|
|
.Equals(aic.SoftwareFilter, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
frequency = (double)filterType;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
APILogger.Log("Could not get software filter: ", ex);
|
|
}
|
|
return frequency;
|
|
}
|
|
|
|
public PreTestDataLine(int datachannel, int rackindex, int moduleindex, Test.Module.Channel channel)
|
|
{
|
|
var aic = channel as Test.Module.AnalogInputChannel;
|
|
|
|
DataChannel = datachannel;
|
|
Rack = rackindex;
|
|
Module = moduleindex;
|
|
Channel = channel.Number + 1;
|
|
|
|
CalDate = DateTime.MinValue;
|
|
CalMode = new CalMode();
|
|
CalMode.Filter = true;
|
|
CalMode.FullBridge = aic.Bridge == SensorConstants.BridgeType.FullBridge;
|
|
CalMode.ShuntCheck = aic.ShuntEnabled;
|
|
CalStep = -1; //emulation
|
|
Category = 0;
|
|
CommentField = aic.ChannelDescriptionString;
|
|
if (string.IsNullOrWhiteSpace(aic.ChannelName2))
|
|
{
|
|
Description = "None";
|
|
}
|
|
else
|
|
{
|
|
Description = aic.ChannelName2; // http://fogbugz/fogbugz/default.asp?10249
|
|
}
|
|
DesiredMaxRange = aic.DesiredRange;
|
|
EU = aic.EngineeringUnits.TrimEnd();
|
|
|
|
try
|
|
{
|
|
ExcitationVoltage = aic.FactoryExcitationVoltage;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
ExcitationVoltage = aic.MeasuredExcitationVoltage;
|
|
}
|
|
ExcitationVoltage = aic.MeasuredExcitationVoltage;
|
|
|
|
Gain = (5000D / ushort.MaxValue) / aic.Data.ScaleFactorMv;
|
|
InitialEU = aic.InitialEu;
|
|
Invert = aic.IsInverted;
|
|
ISOCode = aic.IsoCode;
|
|
Offset = aic.RemoveOffset;
|
|
|
|
OffsetHigh = aic.OffsetToleranceHighMv;
|
|
OffsetLow = aic.OffsetToleranceLowMv;
|
|
ProportionalToExcitation = aic.ProportionalToExcitation;
|
|
Sensitivity = aic.Sensitivity;
|
|
CalDate = aic.LastCalibrationDate;
|
|
SensorId = aic.SensorID;
|
|
SerialNumber = aic.SerialNumber;
|
|
|
|
try
|
|
{
|
|
ShuntValueEU = aic.BridgeResistanceOhms;
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
|
|
SoftwareFilter = Convert.ToInt32(GetFilter(aic));
|
|
|
|
switch (aic.ZeroMethod)
|
|
{
|
|
case ZeroMethodType.AverageOverTime:
|
|
ZeroRef = new ZeroRef(ZeroRef.ZeroType.AverageOverTime);
|
|
break;
|
|
case ZeroMethodType.UsePreEventDiagnosticsZero:
|
|
ZeroRef = new ZeroRef(ZeroRef.ZeroType.UsePreEventDiagnostics);
|
|
break;
|
|
default:
|
|
ZeroRef = new ZeroRef(ZeroRef.ZeroType.UseZeroMv);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public PreTestDataLine(string data)
|
|
{
|
|
var tokens = data.Split(',');
|
|
for (var i = 0; i < tokens.Length; i++)
|
|
{
|
|
var iTemp = int.MinValue;
|
|
var dTemp = double.NegativeInfinity;
|
|
|
|
//we do this as it's safer since some of the inputs may be blank
|
|
int.TryParse(tokens[i], out iTemp);
|
|
double.TryParse(tokens[i], System.Globalization.NumberStyles.Float, TLF.InvariantCulture, out dTemp);
|
|
|
|
switch (i)
|
|
{
|
|
case 0: //datachan
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
DataChannel = iTemp;
|
|
}
|
|
break;
|
|
case 1: //rack
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
Rack = iTemp;
|
|
}
|
|
break;
|
|
case 2: //mod
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
Module = iTemp;
|
|
}
|
|
break;
|
|
case 3: //chan
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
Channel = iTemp;
|
|
}
|
|
break;
|
|
case 4: //desc
|
|
Description = tokens[i];
|
|
break;
|
|
case 5: //s/n
|
|
SerialNumber = tokens[i];
|
|
break;
|
|
case 6: //offsetlow
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
OffsetLow = dTemp;
|
|
}
|
|
break;
|
|
case 7: //ofsethigh
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
OffsetHigh = dTemp;
|
|
}
|
|
break;
|
|
case 8: //calmode
|
|
CalMode = new CalMode(tokens[i]);
|
|
break;
|
|
case 9: //calstep
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
CalStep = dTemp;
|
|
}
|
|
break;
|
|
case 10: //shuntval
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
ShuntValueEU = dTemp;
|
|
}
|
|
break;
|
|
case 11: //proptoext
|
|
if (tokens[i].ToLower() == "n")
|
|
{
|
|
ProportionalToExcitation = false;
|
|
}
|
|
else
|
|
{
|
|
ProportionalToExcitation = true;
|
|
}
|
|
break;
|
|
case 12: //sens
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
Sensitivity = dTemp;
|
|
}
|
|
break;
|
|
case 13: //gain
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
Gain = dTemp;
|
|
}
|
|
break;
|
|
case 14: //extvolt
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
ExcitationVoltage = dTemp;
|
|
}
|
|
break;
|
|
case 15: //EU
|
|
EU = tokens[i];
|
|
break;
|
|
case 16: //filter
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
SoftwareFilter = iTemp;
|
|
}
|
|
break;
|
|
case 17: //invert
|
|
if ("1" == tokens[i])
|
|
{
|
|
Invert = true;
|
|
}
|
|
else
|
|
{
|
|
Invert = false;
|
|
}
|
|
break;
|
|
case 18: //zeroref
|
|
ZeroRef = new ZeroRef(tokens[i]);
|
|
break;
|
|
case 19: //desiredmaxrange
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
DesiredMaxRange = dTemp;
|
|
}
|
|
break;
|
|
case 20: //commentfield
|
|
CommentField = tokens[i];
|
|
break;
|
|
case 21: //caldate
|
|
{
|
|
var subTokens = tokens[i].Split('_');
|
|
if (3 == subTokens.Length)
|
|
{
|
|
CalDate = new DateTime(int.Parse(subTokens[2]), int.Parse(subTokens[0]),
|
|
int.Parse(subTokens[1]));
|
|
}
|
|
}
|
|
break;
|
|
case 22: //offset?
|
|
if (tokens[i].ToLower() == "n")
|
|
{
|
|
Offset = false;
|
|
}
|
|
else
|
|
{
|
|
Offset = true;
|
|
}
|
|
break;
|
|
case 23: //initialEU
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
InitialEU = dTemp;
|
|
}
|
|
break;
|
|
case 24: //sensorid
|
|
SensorId = tokens[i];
|
|
break;
|
|
case 25: //isocode
|
|
ISOCode = tokens[i];
|
|
break;
|
|
case 26: //irtracc exponent
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
IRTRACCExponent = dTemp;
|
|
}
|
|
break;
|
|
case 27: //category
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
Category = iTemp;
|
|
}
|
|
break;
|
|
default:
|
|
throw new NotSupportedException("Invalid number of parameters in Sensor line: " + data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class PostTestDataLine
|
|
{
|
|
public int DataChannel { get; set; }
|
|
|
|
public int Rack { get; set; }
|
|
|
|
public int Module { get; set; }
|
|
|
|
public int Channel { get; set; }
|
|
|
|
public double ActualMaxRange { get; set; }
|
|
|
|
public string PreDiag { get; set; }
|
|
|
|
public double Offset { get; set; }
|
|
|
|
public double SignalToNoiseRatio { get; set; }
|
|
|
|
public double PreZero { get; set; }
|
|
|
|
public int PreCal { get; set; }
|
|
|
|
//volt/cnt
|
|
/// <summary>
|
|
/// DANGER, we aren't using the DataScaler here
|
|
/// (because of the nature of the TLF file it's a little bit ugly to jam in)
|
|
/// tripple check the results of TLF exports!
|
|
/// </summary>
|
|
private double _scaleFactorMV;
|
|
|
|
public double ScaleFactorMV
|
|
{
|
|
get => _scaleFactorMV;
|
|
set => _scaleFactorMV = value;
|
|
}
|
|
|
|
public double ScaleFactorEU { get; set; }
|
|
|
|
public double DataZero { get; set; }
|
|
|
|
public double PostZero { get; set; }
|
|
|
|
public int PostCal { get; set; }
|
|
|
|
public double MaxEU { get; set; }
|
|
|
|
public double MaxTimeMS { get; set; }
|
|
|
|
public double MinEU { get; set; }
|
|
|
|
public double MinTimeMS { get; set; }
|
|
|
|
public bool ChannelSaturated { get; set; }
|
|
|
|
public string PostDiag { get; set; }
|
|
|
|
public long ActualZeroMVCounts { get; set; }
|
|
|
|
public double DesiredMaxRangeScaling { get; set; }
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.Write(DataChannel);
|
|
sw.Write(",");
|
|
sw.Write(Rack);
|
|
sw.Write(",");
|
|
sw.Write(Module);
|
|
sw.Write(",");
|
|
sw.Write(Channel);
|
|
sw.Write(",");
|
|
sw.Write(ActualMaxRange.ToString("F3"));
|
|
sw.Write(",");
|
|
sw.Write(PreDiag);
|
|
sw.Write(",");
|
|
sw.Write(Offset.ToString("F5"));
|
|
sw.Write(",");
|
|
sw.Write(SignalToNoiseRatio.ToString("F5"));
|
|
sw.Write(",");
|
|
sw.Write(PreZero);
|
|
sw.Write(",");
|
|
sw.Write(PreCal);
|
|
sw.Write(",");
|
|
sw.Write(ScaleFactorMV.ToString("F6"));
|
|
sw.Write(",");
|
|
sw.Write(ScaleFactorEU.ToString("F6"));
|
|
sw.Write(",");
|
|
sw.Write(DataZero);
|
|
sw.Write(",");
|
|
sw.Write(PostZero);
|
|
sw.Write(",");
|
|
sw.Write(PostCal);
|
|
sw.Write(",");
|
|
sw.Write(MaxEU.ToString("F6"));
|
|
sw.Write(",");
|
|
sw.Write(MaxTimeMS.ToString("F1"));
|
|
sw.Write(",");
|
|
sw.Write(MinEU.ToString("F6"));
|
|
sw.Write(",");
|
|
sw.Write(MinTimeMS.ToString("F4"));
|
|
sw.Write(",");
|
|
if (ChannelSaturated)
|
|
{
|
|
sw.Write("Y");
|
|
}
|
|
else
|
|
{
|
|
sw.Write("N");
|
|
}
|
|
sw.Write(",");
|
|
sw.Write(PostDiag);
|
|
sw.Write(",");
|
|
sw.Write(ActualZeroMVCounts);
|
|
sw.Write(",");
|
|
sw.Write(DesiredMaxRangeScaling.ToString("F1"));
|
|
sw.Write(sw.NewLine);
|
|
}
|
|
|
|
private string GetPreDiag(Test.Module.Channel channel, double signalToNoiseRatio, double offset)
|
|
{
|
|
var aic = channel as Test.Module.AnalogInputChannel;
|
|
if (null == aic)
|
|
{
|
|
return "PPPPPPP";
|
|
}
|
|
var sb = new StringBuilder();
|
|
|
|
//1 noise level
|
|
//noiseFloorDB = -20 * Math.Log10(3 * stddev / 65536.0);
|
|
//from tdascontrol
|
|
var noiseFloorDB = -20 * Math.Log10(-3 * aic.NoiseAsPercentageOfFullScale / ushort.MinValue);
|
|
if (noiseFloorDB < 0 || noiseFloorDB > 100)
|
|
{
|
|
noiseFloorDB = 0;
|
|
}
|
|
if (noiseFloorDB < 50)
|
|
{
|
|
sb.Append("F");
|
|
}
|
|
else
|
|
{
|
|
sb.Append("P");
|
|
}
|
|
|
|
//step 2 excitationvoltage
|
|
//tdas control also does a little dance around the excitation voltage at -10.1
|
|
//but I'm not really sure why it does that and I'm a little suspicious of it
|
|
//so I leave it out of the implementation
|
|
/*
|
|
* if (-10.1 > extvolt[r][m][c]){
|
|
extvolt[r][m][c] = fabs (extvolt[r][m][c]);
|
|
}*/
|
|
var excitationVoltage = 5D;
|
|
try
|
|
{
|
|
excitationVoltage = aic.FactoryExcitationVoltage;
|
|
}
|
|
catch
|
|
{
|
|
switch (aic.ExcitationVoltage)
|
|
{
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt5:
|
|
excitationVoltage = 5D;
|
|
break;
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt10:
|
|
excitationVoltage = 10D;
|
|
break;
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt2_5:
|
|
excitationVoltage = 2.5D;
|
|
break;
|
|
case ExcitationVoltageOptions.ExcitationVoltageOption.Volt2:
|
|
excitationVoltage = 2D;
|
|
break;
|
|
}
|
|
}
|
|
var measuredExcitation = 5D;
|
|
if (aic.MeasuredExcitationVoltageValid)
|
|
{
|
|
measuredExcitation = aic.MeasuredExcitationVoltage;
|
|
}
|
|
else if (aic.FactoryExcitationVoltageValid)
|
|
{
|
|
measuredExcitation = aic.FactoryExcitationVoltage;
|
|
}
|
|
else
|
|
{
|
|
APILogger.Log("both factory and measured excitation invalid, using 5V instead");
|
|
}
|
|
|
|
var delta = 100D * (excitationVoltage - measuredExcitation) / excitationVoltage;
|
|
if (delta < -2 || delta > 2)
|
|
{
|
|
sb.Append("F");
|
|
}
|
|
else
|
|
{
|
|
sb.Append("P");
|
|
}
|
|
|
|
//offset - this information isn't available yet (offset low/high)
|
|
sb.Append("P");
|
|
|
|
//gain accuracy - range checking isn't available
|
|
sb.Append("P");
|
|
|
|
if (aic.ZeroMethod == ZeroMethodType.None)
|
|
{
|
|
sb.Append("P");
|
|
}
|
|
else
|
|
{
|
|
delta = 100D * aic.PreTestZeroLevelAdc / (-1 * short.MinValue + short.MaxValue);
|
|
if (delta < -5 || delta > 5)
|
|
{
|
|
sb.Append("F");
|
|
}
|
|
else
|
|
{
|
|
sb.Append("P");
|
|
}
|
|
}
|
|
|
|
//signal to noise ratio
|
|
//these seem like _really_ loose ratios ...
|
|
if (signalToNoiseRatio > 90 || signalToNoiseRatio < 0)
|
|
{
|
|
sb.Append("F");
|
|
}
|
|
else
|
|
{
|
|
sb.Append("P");
|
|
}
|
|
|
|
//don't have access to the settings here, so the information needs to be passed in
|
|
if (aic.ShuntEnabled && aic.MeasureShuntDeflectionMvValid && aic.TargetShuntDeflectionMvValid)
|
|
{
|
|
if (aic.MeasuredShuntDeflectionMv < .8 * aic.TargetShuntDeflectionMv ||
|
|
aic.MeasuredShuntDeflectionMv > 2 * aic.TargetShuntDeflectionMv)
|
|
{
|
|
sb.Append("F");
|
|
}
|
|
else
|
|
{
|
|
sb.Append("P");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sb.Append("T");
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
|
|
public PostTestDataLine(int datachan, int rackindex, Test.Module.Channel channel)
|
|
{
|
|
|
|
DataChannel = datachan;
|
|
Rack = rackindex;
|
|
Module = channel.ParentModule.Number + 1;
|
|
Channel = channel.Number + 1;
|
|
var aic = channel as Test.Module.AnalogInputChannel;
|
|
|
|
var stddev = aic.NoiseAsPercentageOfFullScale / (-1D) * short.MinValue;
|
|
stddev /= 100D;
|
|
if (0 == stddev)
|
|
{
|
|
SignalToNoiseRatio = 0D;
|
|
}
|
|
else
|
|
{
|
|
SignalToNoiseRatio = 20D * Math.Log10(-.8D * short.MinValue / stddev);
|
|
}
|
|
|
|
if (aic.ProportionalToExcitation)
|
|
{
|
|
var x = DesiredMaxRangeScaling;
|
|
ActualMaxRange = 0.95 * (aic.DesiredRange /
|
|
(((5000D / ushort.MaxValue) / aic.Data.ScaleFactorMv) *
|
|
aic.Sensitivity * aic.MeasuredExcitationVoltage));
|
|
}
|
|
else
|
|
{
|
|
ActualMaxRange = 0.95 * (aic.DesiredRange /
|
|
(((5000D / ushort.MaxValue) / aic.Data.ScaleFactorMv) *
|
|
aic.Sensitivity));
|
|
}
|
|
|
|
//@TODO - is this the right field?
|
|
ActualZeroMVCounts = 0;
|
|
ChannelSaturated = false;
|
|
|
|
var minValue = short.MaxValue;
|
|
var maxValue = short.MinValue;
|
|
ulong minIndex = 0;
|
|
ulong maxIndex = 0;
|
|
for (ulong i = 0; i < channel.PersistentChannelInfo.NumberOfSamples; i++)
|
|
{
|
|
var sValue = channel.PersistentChannelInfo[i];
|
|
if (sValue < minValue)
|
|
{
|
|
minValue = sValue;
|
|
minIndex = i;
|
|
}
|
|
if (sValue > maxValue)
|
|
{
|
|
maxValue = sValue;
|
|
maxIndex = i;
|
|
}
|
|
if (minValue == short.MinValue && maxValue == short.MaxValue)
|
|
{
|
|
ChannelSaturated = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DataZero = aic.DataZeroLevelAdc;
|
|
DesiredMaxRangeScaling = 1;
|
|
|
|
try
|
|
{
|
|
MaxTimeMS = 1000 * (aic.ParentModule.RequestedPreTriggerSeconds +
|
|
((double)(maxIndex - 1) / aic.ParentModule.SampleRateHz));
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
|
|
try
|
|
{
|
|
MinTimeMS = 1000 * (aic.ParentModule.RequestedPreTriggerSeconds +
|
|
((double)(minIndex - 1) / aic.ParentModule.SampleRateHz));
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
|
|
PostCal = Convert.ToInt32(.8D * short.MaxValue);
|
|
//@TODO - pre and post diagnostics, is it ok for sliceware to just output P's?
|
|
PostDiag = "P";
|
|
PostZero = aic.PreTestZeroLevelAdc;
|
|
PreCal = Convert.ToInt32(.7D * short.MaxValue);
|
|
|
|
PreZero = aic.PreTestZeroLevelAdc;
|
|
|
|
var excitationVoltage = 5D;
|
|
//if (slice) to-do: use FactoryExcitationVoltage if this is SLICE hardware
|
|
//{
|
|
try
|
|
{
|
|
excitationVoltage = aic.FactoryExcitationVoltage;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
excitationVoltage = aic.MeasuredExcitationVoltage;
|
|
}
|
|
//}
|
|
//else
|
|
//{
|
|
excitationVoltage = aic.MeasuredExcitationVoltage;
|
|
//}
|
|
|
|
if (aic.ProportionalToExcitation)
|
|
{
|
|
ScaleFactorEU = aic.Data.ScaleFactorMv / (excitationVoltage * aic.Data.MvPerEu);
|
|
}
|
|
else
|
|
{
|
|
ScaleFactorEU = aic.Data.ScaleFactorMv / aic.Data.MvPerEu;
|
|
}
|
|
|
|
if (aic.IsInverted)
|
|
{
|
|
ScaleFactorEU *= -1D;
|
|
}
|
|
|
|
|
|
|
|
ScaleFactorMV = aic.Data.ScaleFactorMv;
|
|
Offset = aic.DataZeroLevelAdc * ScaleFactorMV;
|
|
|
|
MaxEU = ScaleFactorEU * (maxValue - aic.DataZeroLevelAdc);
|
|
MinEU = ScaleFactorEU * (minValue - aic.DataZeroLevelAdc);
|
|
|
|
PreDiag = GetPreDiag(channel, SignalToNoiseRatio, Offset);
|
|
}
|
|
|
|
public PostTestDataLine(string data)
|
|
{
|
|
var tokens = data.Split(',');
|
|
for (var i = 0; i < tokens.Length; i++)
|
|
{
|
|
var dTemp = double.NegativeInfinity;
|
|
var iTemp = int.MinValue;
|
|
double.TryParse(tokens[i], System.Globalization.NumberStyles.Float, TLF.InvariantCulture, out dTemp);
|
|
int.TryParse(tokens[i], out iTemp);
|
|
switch (i)
|
|
{
|
|
case 0: //datachan
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
DataChannel = iTemp;
|
|
}
|
|
break;
|
|
case 1: //rack
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
Rack = iTemp;
|
|
}
|
|
break;
|
|
case 2: //mod
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
Module = iTemp;
|
|
}
|
|
break;
|
|
case 3: //chan
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
Channel = iTemp;
|
|
}
|
|
break;
|
|
case 4: //actmaxrange
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
ActualMaxRange = dTemp;
|
|
}
|
|
break;
|
|
case 5: //prediag
|
|
PreDiag = tokens[i];
|
|
break;
|
|
case 6: //offsetmv
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
Offset = dTemp;
|
|
}
|
|
break;
|
|
case 7: //snRatio(dB)
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
SignalToNoiseRatio = dTemp;
|
|
}
|
|
break;
|
|
case 8: //prezero
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
PreZero = iTemp;
|
|
}
|
|
break;
|
|
case 9: //precal
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
PreCal = iTemp;
|
|
}
|
|
break;
|
|
case 10: //scalefactormv
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
ScaleFactorMV = dTemp;
|
|
}
|
|
break;
|
|
case 11: //scalefactoreu
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
ScaleFactorEU = dTemp;
|
|
}
|
|
break;
|
|
case 12: //datazero
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
DataZero = iTemp;
|
|
}
|
|
break;
|
|
case 13: //postzero
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
PostZero = iTemp;
|
|
}
|
|
break;
|
|
case 14: //postcal
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
PostCal = iTemp;
|
|
}
|
|
break;
|
|
case 15: //maxeu
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
MaxEU = dTemp;
|
|
}
|
|
break;
|
|
case 16: //maxtime(msec)
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
MaxTimeMS = dTemp;
|
|
}
|
|
break;
|
|
case 17: //min(eu)
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
MinEU = dTemp;
|
|
}
|
|
break;
|
|
case 18: //mintime(msec)
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
MinTimeMS = dTemp;
|
|
}
|
|
break;
|
|
case 19: //chansat
|
|
if (tokens[i].ToLower() != "n")
|
|
{
|
|
ChannelSaturated = true;
|
|
}
|
|
else
|
|
{
|
|
ChannelSaturated = false;
|
|
}
|
|
break;
|
|
case 20: //postdiag
|
|
PostDiag = tokens[i];
|
|
break;
|
|
case 21: //actual 0mv
|
|
if (int.MinValue != iTemp)
|
|
{
|
|
ActualZeroMVCounts = iTemp;
|
|
}
|
|
break;
|
|
case 22: //desired max range scaling
|
|
if (!double.IsNegativeInfinity(dTemp))
|
|
{
|
|
DesiredMaxRangeScaling = dTemp;
|
|
}
|
|
break;
|
|
default:
|
|
throw new NotSupportedException("invalid number of parameters in sensor line: " + data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class CalculatedChannelLine
|
|
{
|
|
private readonly List<string> _values = new List<string>();
|
|
|
|
private enum Fields
|
|
{
|
|
chan = 0,
|
|
descrip,
|
|
processtype,
|
|
firstchan,
|
|
secondchan,
|
|
thirdchan,
|
|
value,
|
|
EU,
|
|
expmaxrange
|
|
}
|
|
|
|
private readonly Fields LastField = Fields.expmaxrange;
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
for (var i = 0; i <= (int)LastField; i++)
|
|
{
|
|
if (i > 0)
|
|
{
|
|
sw.Write(",");
|
|
}
|
|
sw.Write(_values[i]);
|
|
}
|
|
sw.Write(sw.NewLine);
|
|
}
|
|
|
|
public CalculatedChannelLine(string data)
|
|
{
|
|
for (var i = 0; i <= (int)LastField; i++)
|
|
{
|
|
_values.Add("");
|
|
}
|
|
var tokens = data.Split(',');
|
|
if (tokens.Length > _values.Count)
|
|
{
|
|
throw new NotSupportedException("Unexpected number of parameters " + data);
|
|
}
|
|
for (var i = 0; i < tokens.Length; i++)
|
|
{
|
|
_values[i] = tokens[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
//SQUIBFireChannels
|
|
//rack,module,chan,descrip,id,type,
|
|
internal class TOMSQUIBFireLine
|
|
{
|
|
public int Rack { get; set; }
|
|
|
|
public int Module { get; set; }
|
|
|
|
public int Channel { get; set; }
|
|
|
|
public string Description { get; set; }
|
|
|
|
public string Id { get; set; }
|
|
|
|
public int ChannelType { get; set; }
|
|
|
|
public string Current { get; set; }
|
|
|
|
public string Delay { get; set; }
|
|
|
|
public string DurationOn { get; set; }
|
|
|
|
public string Duration { get; set; }
|
|
|
|
public string OhmLow { get; set; }
|
|
|
|
public string OhmHigh { get; set; }
|
|
|
|
public string ISOCode { get; set; }
|
|
|
|
public double MeasuredOhms { get; set; }
|
|
|
|
public string RecordType { get; set; }
|
|
|
|
public string ScaleFactor1 { get; set; }
|
|
|
|
public string ScaleFactor2 { get; set; }
|
|
|
|
public string PostMeasuredOhms { get; set; }
|
|
|
|
public string VoltageZeroAverageADC { get; set; }
|
|
|
|
public string CurrentZeroAverageADC { get; set; }
|
|
|
|
private readonly List<string> _values = new List<string>();
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
//for (int i = 0; i <= (int)LastField; i++)
|
|
//{
|
|
// if (i > 0) { sw.Write(","); }
|
|
// sw.Write(_values[i]);
|
|
//}
|
|
//sw.Write(sw.NewLine);
|
|
sw.Write(Rack);
|
|
sw.Write(",");
|
|
sw.Write(Module);
|
|
sw.Write(",");
|
|
sw.Write(Channel);
|
|
sw.Write(",");
|
|
sw.Write(Description);
|
|
sw.Write(",");
|
|
sw.Write(Id);
|
|
sw.Write(",");
|
|
sw.Write(ChannelType);
|
|
sw.Write(",");
|
|
sw.Write(Current);
|
|
sw.Write(",");
|
|
sw.Write(Delay);
|
|
sw.Write(",");
|
|
sw.Write(DurationOn);
|
|
sw.Write(",");
|
|
sw.Write(Duration);
|
|
sw.Write(",");
|
|
sw.Write(OhmLow);
|
|
sw.Write(",");
|
|
sw.Write(OhmHigh);
|
|
sw.Write(",");
|
|
sw.Write(ISOCode);
|
|
sw.Write(",");
|
|
sw.Write(MeasuredOhms);
|
|
sw.Write(",");
|
|
sw.Write(RecordType);
|
|
sw.Write(",");
|
|
sw.Write(ScaleFactor1);
|
|
sw.Write(",");
|
|
sw.Write(ScaleFactor2);
|
|
sw.Write(",");
|
|
sw.Write(PostMeasuredOhms);
|
|
sw.Write(",");
|
|
sw.Write(VoltageZeroAverageADC);
|
|
sw.Write(",");
|
|
sw.Write(CurrentZeroAverageADC);
|
|
sw.Write(sw.NewLine);
|
|
}
|
|
|
|
public TOMSQUIBFireLine(int rackIndex, Test.Module.Channel channel)
|
|
{
|
|
var aic = channel as Test.Module.AnalogInputChannel;
|
|
|
|
Rack = rackIndex;
|
|
Module = channel.ParentModule.Number + 1;
|
|
switch (channel.Number)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
Channel = 1;
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
Channel = 2;
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
Channel = 3;
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
Channel = 4;
|
|
break;
|
|
}
|
|
if (string.IsNullOrWhiteSpace(aic.Description))
|
|
{
|
|
Description = "None";
|
|
}
|
|
else
|
|
{
|
|
Description = aic.Description;
|
|
}
|
|
Id = aic.SensorID;
|
|
ChannelType = TLF.CHANNEL_TYPE_SQUIB;
|
|
//Needed: current,delay,durationON,duration,OhmLow,OhmHigh,ISO Code,measuredohms,recordtype,scalefactor1,scalefactor2,postmeasuredohms,voltage zero average ADC,current zero average ADC
|
|
//Also needed: combine both TOM channels into one line
|
|
}
|
|
|
|
public TOMSQUIBFireLine(string data)
|
|
{
|
|
for (var i = 0; i <= (int)LastField; i++)
|
|
{
|
|
_values.Add("");
|
|
}
|
|
var tokens = data.Split(',');
|
|
if (tokens.Length > _values.Count)
|
|
{
|
|
throw new NotSupportedException("Unexpected number of parameters " + data);
|
|
}
|
|
for (var i = 0; i < tokens.Length; i++)
|
|
{
|
|
_values[i] = tokens[i];
|
|
}
|
|
}
|
|
|
|
private readonly Fields LastField = Fields.currentZeroAverageADC;
|
|
|
|
private enum Fields
|
|
{
|
|
rack = 0,
|
|
module,
|
|
chan,
|
|
descrip,
|
|
id,
|
|
type,
|
|
current,
|
|
delay,
|
|
durationON,
|
|
duration,
|
|
OhmLow,
|
|
OhmHigh,
|
|
ISOCode,
|
|
measuredohms,
|
|
recordtype,
|
|
scalefactor1,
|
|
scalefactor2,
|
|
postmeasuredohms,
|
|
voltageZeroAverageADC,
|
|
currentZeroAverageADC
|
|
};
|
|
}
|
|
|
|
internal class TOMDigitalChannelLine
|
|
{
|
|
private readonly List<string> _values = new List<string>();
|
|
|
|
private enum Fields
|
|
{
|
|
rack = 0,
|
|
module,
|
|
chan,
|
|
type,
|
|
delay,
|
|
durationON,
|
|
duration
|
|
}
|
|
|
|
private readonly Fields LastField = Fields.duration;
|
|
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
for (var i = 0; i <= (int)LastField; i++)
|
|
{
|
|
if (i > 0)
|
|
{
|
|
sw.Write(",");
|
|
}
|
|
sw.Write(_values[i]);
|
|
}
|
|
sw.Write(sw.NewLine);
|
|
}
|
|
|
|
public TOMDigitalChannelLine(string data)
|
|
{
|
|
for (var i = 0; i <= (int)LastField; i++)
|
|
{
|
|
_values.Add("");
|
|
}
|
|
var tokens = data.Split(',');
|
|
if (tokens.Length > _values.Count)
|
|
{
|
|
throw new NotSupportedException("Unexpected number of parameters " + data);
|
|
}
|
|
for (var i = 0; i < tokens.Length; i++)
|
|
{
|
|
_values[i] = tokens[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class DIMLine
|
|
{
|
|
private readonly List<string> _values = new List<string>();
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.Write(DataChannel);
|
|
sw.Write(",");
|
|
sw.Write(Rack);
|
|
sw.Write(",");
|
|
sw.Write(Module);
|
|
sw.Write(",");
|
|
sw.Write(Channel);
|
|
sw.Write(",");
|
|
sw.Write(Description);
|
|
sw.Write(",");
|
|
sw.Write(SerialNo);
|
|
sw.Write(",");
|
|
sw.Write(Mode);
|
|
sw.Write(",");
|
|
sw.Write(Inverted);
|
|
sw.Write(",");
|
|
sw.Write(EID);
|
|
sw.Write(",");
|
|
sw.Write(Filename);
|
|
sw.Write(",");
|
|
sw.Write(Scale.ToString("F6"));
|
|
sw.Write(",");
|
|
sw.Write(FilterMode);
|
|
sw.Write(",");
|
|
sw.Write(FilterThreshold.ToString("F6"));
|
|
sw.Write(",");
|
|
sw.Write(ISOCODE);
|
|
sw.Write(",");
|
|
sw.Write(CableTest);
|
|
sw.Write(",");
|
|
sw.Write(PreTestResults);
|
|
sw.Write(",");
|
|
sw.Write(PostTestResults);
|
|
sw.Write(sw.NewLine);
|
|
}
|
|
|
|
private readonly Fields LastField = Fields.PostTestResults;
|
|
|
|
private enum Fields
|
|
{
|
|
Datachan = 0,
|
|
Rack,
|
|
Module,
|
|
Chan,
|
|
Description,
|
|
SerialNo,
|
|
Mode,
|
|
Inverted,
|
|
EID,
|
|
Filename,
|
|
Scale,
|
|
FilterMode,
|
|
FilterThreshold,
|
|
ISOCODE,
|
|
CableTest,
|
|
PreTestResults,
|
|
PostTestResults
|
|
}
|
|
|
|
public int DataChannel { get; set; }
|
|
|
|
public int Rack { get; set; }
|
|
|
|
public int Module { get; set; }
|
|
|
|
public int Channel { get; set; }
|
|
|
|
public string Description { get; set; }
|
|
|
|
public string SerialNo { get; set; }
|
|
|
|
public DigitalInputModes Mode { get; set; }
|
|
|
|
public int Inverted { get; set; }
|
|
|
|
public string EID { get; set; }
|
|
|
|
public string Filename { get; set; }
|
|
|
|
public double Scale { get; set; }
|
|
|
|
public int FilterMode { get; set; }
|
|
|
|
public double FilterThreshold { get; set; }
|
|
|
|
public string ISOCODE { get; set; }
|
|
|
|
public int CableTest { get; set; }
|
|
|
|
public string PreTestResults { get; set; }
|
|
|
|
public string PostTestResults { get; set; }
|
|
|
|
public DIMLine(int dataChannel, int rackIndex, Test.Module.Channel channel)
|
|
{
|
|
var aic = channel as Test.Module.AnalogInputChannel;
|
|
|
|
DataChannel = dataChannel;
|
|
Rack = rackIndex;
|
|
Module = channel.ParentModule.Number;
|
|
Channel = channel.Number + 1;
|
|
Description = channel.ChannelDescriptionString;
|
|
if (string.IsNullOrWhiteSpace(channel.SensorID))
|
|
{
|
|
SerialNo = "No Sensor";
|
|
}
|
|
else
|
|
{
|
|
SerialNo = channel.SensorID;
|
|
}
|
|
Mode = aic.DigitalMode;
|
|
if (aic.IsInverted)
|
|
{
|
|
Inverted = 1;
|
|
}
|
|
else
|
|
{
|
|
Inverted = 0;
|
|
}
|
|
if (string.IsNullOrWhiteSpace(channel.SensorID))
|
|
{
|
|
EID = "NONE";
|
|
}
|
|
else
|
|
{
|
|
EID = channel.SensorID;
|
|
}
|
|
Filename = string.Empty;
|
|
Scale = aic.DigitalMultiplier.ActiveValue;
|
|
FilterMode = 1; //None=1; Latch=2; Debounce=3
|
|
FilterThreshold = 10.000000; //The default
|
|
ISOCODE = aic.IsoCode;
|
|
CableTest = 0; //No=0; Yes=1
|
|
PreTestResults = "PPPP"; //The default
|
|
PostTestResults = "PPPP"; //The default
|
|
|
|
}
|
|
|
|
public DIMLine(string data)
|
|
{
|
|
for (var i = 0; i <= (int)LastField; i++)
|
|
{
|
|
_values.Add("");
|
|
}
|
|
var tokens = data.Split(',');
|
|
if (tokens.Length > _values.Count)
|
|
{
|
|
throw new NotSupportedException("Unexpected number of parameters " + data);
|
|
}
|
|
for (var i = 0; i < tokens.Length; i++)
|
|
{
|
|
_values[i] = tokens[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class G5DigitalChannelLine
|
|
{
|
|
private readonly List<string> _values = new List<string>();
|
|
|
|
private enum Fields
|
|
{
|
|
datachan = 0,
|
|
rack,
|
|
mod,
|
|
chan,
|
|
descrip,
|
|
ISOCode,
|
|
scale,
|
|
invert
|
|
}
|
|
|
|
public int DataChannel { get; set; }
|
|
|
|
public int Rack { get; set; }
|
|
|
|
public int Module { get; set; }
|
|
|
|
public int Channel { get; set; }
|
|
|
|
public string Description { get; set; }
|
|
|
|
public string ISOCode { get; set; }
|
|
|
|
public double Scale { get; set; }
|
|
|
|
public int Invert { get; set; }
|
|
|
|
readonly Fields LastField = Fields.invert;
|
|
|
|
public G5DigitalChannelLine(int dataChannel, int rackIndex, Test.Module.Channel channel)
|
|
{
|
|
var aic = channel as Test.Module.AnalogInputChannel;
|
|
|
|
DataChannel = dataChannel;
|
|
Rack = rackIndex;
|
|
Module = channel.ParentModule.Number + 1;
|
|
Channel = channel.Number + 1;
|
|
Description = channel.ChannelDescriptionString;
|
|
ISOCode = aic.IsoCode;
|
|
Scale = aic.DigitalMultiplier.ActiveValue;
|
|
if (aic.IsInverted)
|
|
{
|
|
Invert = 1;
|
|
}
|
|
else
|
|
{
|
|
Invert = 0;
|
|
}
|
|
}
|
|
|
|
public G5DigitalChannelLine(string data)
|
|
{
|
|
for (var i = 0; i <= (int)LastField; i++)
|
|
{
|
|
_values.Add("");
|
|
}
|
|
var tokens = data.Split(',');
|
|
if (tokens.Length > _values.Count)
|
|
{
|
|
throw new NotSupportedException("Unexpected number of parameters " + data);
|
|
}
|
|
for (var i = 0; i < tokens.Length; i++)
|
|
{
|
|
if ((int)Fields.datachan == i)
|
|
{
|
|
int datachan;
|
|
if (int.TryParse(tokens[i], out datachan))
|
|
{
|
|
DataChannel = datachan;
|
|
}
|
|
}
|
|
_values[i] = tokens[i];
|
|
}
|
|
}
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.Write(DataChannel);
|
|
sw.Write(",");
|
|
sw.Write(Rack);
|
|
sw.Write(",");
|
|
sw.Write(Module);
|
|
sw.Write(",");
|
|
sw.Write(Channel);
|
|
sw.Write(",");
|
|
sw.Write(Description);
|
|
sw.Write(",");
|
|
sw.Write(ISOCode);
|
|
sw.Write(",");
|
|
sw.Write(Scale.ToString("F1"));
|
|
sw.Write(",");
|
|
sw.Write(Invert);
|
|
sw.Write(sw.NewLine);
|
|
}
|
|
}
|
|
|
|
internal class SensorChannelSection : TLFSection
|
|
{
|
|
public int ExistingChannels => _preTestData.NumberOfLines;
|
|
|
|
public int LastChannel => _preTestData.LastDataChannel;
|
|
|
|
private readonly PreTestDataSection _preTestData = new PreTestDataSection();
|
|
private readonly PostTestDataSection _postTestData = new PostTestDataSection();
|
|
|
|
public int StartingSLICEChannel
|
|
{
|
|
set
|
|
{
|
|
_preTestData.StartingSLICEChannel = value;
|
|
_postTestData.StartingSliceChannel = value;
|
|
}
|
|
}
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.WriteLine("---- Start Sensor Channel Information ----");
|
|
_preTestData.Serialize(sw);
|
|
_postTestData.Serialize(sw);
|
|
sw.WriteLine("---- End Sensor Channel Information ----");
|
|
}
|
|
|
|
public void AddTestData(Test test, TLF.Rack[] racks, Dictionary<string, int> moduleSNToRackIdx)
|
|
{
|
|
_preTestData.AddTestData(test, racks, moduleSNToRackIdx);
|
|
_postTestData.AddTestData(test, racks, moduleSNToRackIdx);
|
|
}
|
|
|
|
public void ReadTestData(System.IO.StreamReader sr)
|
|
{
|
|
sr.ReadLine(); //start sensor channel information
|
|
|
|
var curState = 0;
|
|
while (sr.Peek() != '-')
|
|
{
|
|
var line = sr.ReadLine();
|
|
if (line == "PreTest Data")
|
|
{
|
|
curState = 1;
|
|
sr.ReadLine(); //parameters;
|
|
}
|
|
else if (line == "PostTest Data")
|
|
{
|
|
curState = 2;
|
|
sr.ReadLine(); //parameters
|
|
}
|
|
else
|
|
{
|
|
if (1 == curState)
|
|
{
|
|
_preTestData.ReadTestData(line);
|
|
}
|
|
else if (2 == curState)
|
|
{
|
|
_postTestData.ReadTestData(line);
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException("unexpected data in sensor channel section: " + line);
|
|
}
|
|
}
|
|
}
|
|
sr.ReadLine(); //endSensorChannelInformation
|
|
}
|
|
}
|
|
|
|
internal class PreTestDataSection : TLFSection
|
|
{
|
|
|
|
private readonly List<PreTestDataLine> _lines = new List<PreTestDataLine>();
|
|
|
|
public int NumberOfLines => _lines.Count;
|
|
|
|
public int StartingSLICEChannel { get; set; } = int.MinValue;
|
|
|
|
public int LastDataChannel
|
|
{
|
|
get
|
|
{
|
|
if (_lines.Count < 1)
|
|
{
|
|
return 0;
|
|
}
|
|
var maxExiting = _lines.Max(ptdl => ptdl.DataChannel);
|
|
return Math.Max(maxExiting, StartingSLICEChannel);
|
|
}
|
|
}
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.WriteLine("PreTest Data");
|
|
sw.WriteLine(
|
|
"datachan,rack,mod,chan,descrip,s/n,offsetlow,offsethigh,calmode,calstep(ohm/volt),shuntval(eu),proptoext,sens(mv/eu or mv/v/eu),gain,extvolt,EU,filter,invert,zeroref,desiredmaxrange,commentfield,caldate,Offset?,InitialEU,sensorID,ISOcode,IRTRACC Exponent,Category");
|
|
if (null != _lines)
|
|
{
|
|
foreach (var line in _lines)
|
|
{
|
|
line.Serialize(sw);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void AddTestData(Test test, TLF.Rack[] racks, Dictionary<string, int> moduleSNToRackIdx)
|
|
{
|
|
foreach (var channel in test.Channels)
|
|
{
|
|
if ((!(channel as Test.Module.AnalogInputChannel).IsSquibChannel) &&
|
|
((channel as Test.Module.AnalogInputChannel).Bridge !=
|
|
SensorConstants.BridgeType.DigitalInput))
|
|
{
|
|
var serialNumber = channel.ParentModule.SerialNumber;
|
|
|
|
var rack = racks[moduleSNToRackIdx[serialNumber]];
|
|
var dataChannel = LastDataChannel + 1;
|
|
var rackIndex = rack.RackIndex;
|
|
var moduleIndex = channel.ParentModule.Number + 1;
|
|
_lines.Add(new PreTestDataLine(dataChannel, rackIndex, moduleIndex, channel));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ReadTestData(string line)
|
|
{
|
|
_lines.Add(new PreTestDataLine(line));
|
|
}
|
|
}
|
|
|
|
internal class PostTestDataSection : TLFSection
|
|
{
|
|
private readonly List<PostTestDataLine> _lines = new List<PostTestDataLine>();
|
|
|
|
public int StartingSliceChannel { get; set; } = int.MinValue;
|
|
|
|
public int LastDataChannel
|
|
{
|
|
get
|
|
{
|
|
if (_lines.Count < 1)
|
|
{
|
|
return 0;
|
|
}
|
|
var maxExiting = _lines.Max(ptdl => ptdl.DataChannel);
|
|
return Math.Max(maxExiting, StartingSliceChannel);
|
|
}
|
|
}
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.WriteLine("PostTest Data");
|
|
sw.WriteLine(
|
|
"datachan,rack,mod,chan,actmaxrange,prediag,offset(mv),SNRatio(dB),prezero,precal,scalefactor(volts/cnt),scalefactor(eu/cnt),datazero,postzero,postcal,max(eu),maxtime(msec),min(eu),mintime(msec),chansat,postdiag,actual 0 mV cnts,desired max range scaling");
|
|
if (null != _lines)
|
|
{
|
|
foreach (var line in _lines)
|
|
{
|
|
line.Serialize(sw);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void AddTestData(Test test, TLF.Rack[] racks, Dictionary<string, int> moduleSNToRackIdx)
|
|
{
|
|
foreach (var channel in test.Channels)
|
|
{
|
|
if ((!(channel as Test.Module.AnalogInputChannel).IsSquibChannel) &&
|
|
((channel as Test.Module.AnalogInputChannel).Bridge !=
|
|
SensorConstants.BridgeType.DigitalInput))
|
|
{
|
|
var dataChannel = LastDataChannel + 1;
|
|
var serialNumber = channel.ParentModule.SerialNumber;
|
|
|
|
var rack = racks[moduleSNToRackIdx[serialNumber]];
|
|
var rackIndex = rack.RackIndex;
|
|
_lines.Add(new PostTestDataLine(dataChannel, rackIndex, channel));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ReadTestData(string line)
|
|
{
|
|
_lines.Add(new PostTestDataLine(line));
|
|
}
|
|
}
|
|
|
|
internal class CalculatedChannelSection : TLFSection
|
|
{
|
|
private readonly List<CalculatedChannelLine> _lines = new List<CalculatedChannelLine>();
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.WriteLine("---- Start Calculated Channel Information ----");
|
|
sw.WriteLine("chan,descrip,processtype,1stchan,2ndchan,3rdchan,value,EU,expmaxrange");
|
|
if (null != _lines)
|
|
{
|
|
foreach (var line in _lines)
|
|
{
|
|
line.Serialize(sw);
|
|
}
|
|
}
|
|
sw.WriteLine("---- End Calculated Channel Information ----");
|
|
}
|
|
|
|
public void AddTestData()
|
|
{
|
|
}
|
|
|
|
public void ReadTestData(System.IO.StreamReader sr)
|
|
{
|
|
sr.ReadLine(); //start calculated
|
|
sr.ReadLine(); //parameters
|
|
while (sr.Peek() != '-')
|
|
{
|
|
_lines.Add(new CalculatedChannelLine(sr.ReadLine()));
|
|
}
|
|
|
|
sr.ReadLine(); //end calculated
|
|
}
|
|
}
|
|
|
|
internal class TOMSection : TLFSection
|
|
{
|
|
private readonly TOMSquibFireSection _squibFireSection = new TOMSquibFireSection();
|
|
private readonly TOMDigitalChannelsSection _digitalChannelsSection = new TOMDigitalChannelsSection();
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.WriteLine("---- Start TOM Channel Information ----");
|
|
_squibFireSection.Serialize(sw);
|
|
_digitalChannelsSection.Serialize(sw);
|
|
sw.WriteLine("---- End TOM Channel Information ----");
|
|
}
|
|
|
|
public void AddTestData(Test test, TLF.Rack[] racks, Dictionary<string, int> moduleSNToRackIdx)
|
|
{
|
|
_squibFireSection.AddTestData(test, racks, moduleSNToRackIdx);
|
|
_digitalChannelsSection.AddTestData(test, racks);
|
|
}
|
|
|
|
public void ReadTestData(System.IO.StreamReader sr)
|
|
{
|
|
sr.ReadLine(); //start tom channel info
|
|
sr.ReadLine(); //squib fire channels
|
|
sr.ReadLine(); //parameters
|
|
while (sr.Peek() != '-')
|
|
{
|
|
_squibFireSection.ReadTestData(sr.ReadLine());
|
|
}
|
|
sr.ReadLine(); //tom digital channels
|
|
sr.ReadLine(); //parameters
|
|
while (sr.Peek() != '-')
|
|
{
|
|
_digitalChannelsSection.ReadTestData(sr.ReadLine());
|
|
}
|
|
sr.ReadLine(); //end tom channel information
|
|
}
|
|
}
|
|
|
|
internal class TOMSquibFireSection : TLFSection
|
|
{
|
|
private readonly List<TOMSQUIBFireLine> _lines = new List<TOMSQUIBFireLine>();
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.WriteLine("---- TOM Squib Fire Channels ----");
|
|
sw.WriteLine(
|
|
"rack,module,chan,descrip,id,type,current,delay,durationON,duration,OhmLow,OhmHigh,ISO Code,measuredohms,recordtype,scalefactor1,scalefactor2,postmeasuredohms,voltage zero average ADC,current zero average ADC");
|
|
if (null != _lines)
|
|
{
|
|
foreach (var line in _lines)
|
|
{
|
|
line.Serialize(sw);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void AddTestData(Test test, TLF.Rack[] racks, Dictionary<string, int> moduleSNToRackIdx)
|
|
{
|
|
foreach (var channel in test.Channels)
|
|
{
|
|
var result = 0;
|
|
//Only output one line for each Current/Voltage pair of squib channels
|
|
Math.DivRem(channel.Number, 2, out result);
|
|
if ((channel as Test.Module.AnalogInputChannel).IsSquibChannel && (result == 0))
|
|
{
|
|
var serialNumber = channel.ParentModule.SerialNumber;
|
|
|
|
var rack = racks[moduleSNToRackIdx[serialNumber]];
|
|
var rackIndex = rack.RackIndex;
|
|
|
|
_lines.Add(new TOMSQUIBFireLine(rackIndex, channel));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ReadTestData(string data)
|
|
{
|
|
_lines.Add(new TOMSQUIBFireLine(data));
|
|
}
|
|
}
|
|
|
|
internal class TOMDigitalChannelsSection : TLFSection
|
|
{
|
|
private readonly List<TOMDigitalChannelLine> _lines = new List<TOMDigitalChannelLine>();
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.WriteLine("---- TOM Digital Channels ----");
|
|
sw.WriteLine("rack,module,chan,type,delay,durationON,duration");
|
|
if (null != _lines)
|
|
{
|
|
foreach (var line in _lines)
|
|
{
|
|
line.Serialize(sw);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void AddTestData(Test test, TLF.Rack[] racks)
|
|
{
|
|
}
|
|
|
|
public void ReadTestData(string s)
|
|
{
|
|
_lines.Add(new TOMDigitalChannelLine(s));
|
|
}
|
|
}
|
|
|
|
internal class DIMSection : TLFSection
|
|
{
|
|
public int LastChannel { get; } = int.MinValue;
|
|
|
|
private readonly List<DIMLine> _lines = new List<DIMLine>();
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.WriteLine("---- DIM Begin (1.0) ----");
|
|
sw.WriteLine(
|
|
"Datachan,Rack,Module,Chan,Description,Serial No,Mode,Inverted,EID,Filename,Scale,Filter Mode,Filter Threshold,ISO CODE,Cable Test,Pre Test Results, Post TestResults");
|
|
if (null != _lines)
|
|
{
|
|
foreach (var line in _lines)
|
|
{
|
|
line.Serialize(sw);
|
|
}
|
|
}
|
|
sw.WriteLine("---- DIM End ----");
|
|
}
|
|
|
|
private static bool IsG5(Test.Module.Channel channel)
|
|
{
|
|
return channel.ParentModule.BaseSerialNumber.StartsWith("5M");
|
|
}
|
|
|
|
public void AddTestData(Test test, TLF.Rack[] racks, Dictionary<string, int> moduleSNToRackIdx, int lastChannel)
|
|
{
|
|
var LastChannel = lastChannel;
|
|
foreach (var channel in test.Channels)
|
|
{
|
|
if (((channel as Test.Module.AnalogInputChannel).Bridge ==
|
|
SensorConstants.BridgeType.DigitalInput) &&
|
|
(!IsG5(channel)))
|
|
{
|
|
var serialNumber = channel.ParentModule.SerialNumber;
|
|
|
|
var dataChannel = LastChannel + 1;
|
|
LastChannel++;
|
|
var rack = racks[moduleSNToRackIdx[serialNumber]];
|
|
var rackIndex = rack.RackIndex;
|
|
|
|
_lines.Add(new DIMLine(dataChannel, rackIndex, channel));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ReadTestData(System.IO.StreamReader sr)
|
|
{
|
|
sr.ReadLine(); //dimbegin
|
|
sr.ReadLine(); //parameters
|
|
while (sr.Peek() != '-')
|
|
{
|
|
_lines.Add(new DIMLine(sr.ReadLine()));
|
|
}
|
|
sr.ReadLine(); //dimend
|
|
}
|
|
}
|
|
|
|
internal class G5DigitalChannelsSection : TLFSection
|
|
{
|
|
public int LastChannel { get; private set; } = int.MinValue;
|
|
|
|
private readonly List<G5DigitalChannelLine> _lines = new List<G5DigitalChannelLine>();
|
|
|
|
public void Serialize(System.IO.StreamWriter sw)
|
|
{
|
|
sw.WriteLine("---- G5 Digital Input Channels Begin ----");
|
|
sw.WriteLine("datachan,rack,mod,chan,descrip,ISOCode,scale,invert");
|
|
if (null != _lines)
|
|
{
|
|
foreach (var line in _lines)
|
|
{
|
|
line.Serialize(sw);
|
|
}
|
|
}
|
|
sw.WriteLine("---- G5 Digital Input Channels End ----");
|
|
}
|
|
|
|
private static bool IsG5(Test.Module.Channel channel)
|
|
{
|
|
return channel.ParentModule.BaseSerialNumber.StartsWith("5M");
|
|
}
|
|
|
|
public void AddTestData(Test test, TLF.Rack[] racks, Dictionary<string, int> moduleSNToRackIdx, int lastChannel)
|
|
{
|
|
var LastChannel = lastChannel;
|
|
foreach (var channel in test.Channels)
|
|
{
|
|
if (((channel as Test.Module.AnalogInputChannel).Bridge ==
|
|
SensorConstants.BridgeType.DigitalInput) &&
|
|
(IsG5(channel)))
|
|
{
|
|
var serialNumber = channel.ParentModule.SerialNumber;
|
|
|
|
var dataChannel = LastChannel + 1;
|
|
LastChannel++;
|
|
var rack = racks[moduleSNToRackIdx[serialNumber]];
|
|
var rackIndex = rack.RackIndex;
|
|
|
|
_lines.Add(new G5DigitalChannelLine(dataChannel, rackIndex, channel));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ReadTestData(System.IO.StreamReader sr)
|
|
{
|
|
sr.ReadLine(); //g5digital begin
|
|
sr.ReadLine(); //parameters
|
|
while (sr.Peek() != '-')
|
|
{
|
|
var g5 = new G5DigitalChannelLine(sr.ReadLine());
|
|
_lines.Add(g5);
|
|
LastChannel = Math.Max(LastChannel, g5.DataChannel);
|
|
}
|
|
sr.ReadLine(); //end line
|
|
}
|
|
}
|
|
}
|