Files
2026-04-17 14:55:32 -04:00

11843 lines
600 KiB
C#

//FB 32926 Old location of this file is \DataPRO\DataPRO\DataModel\Classes\TestTemplate\TestTemplate.cs
using DataPROWin7.Common;
using DataPROWin7.DataModel.Classes.Hardware;
using DataPROWin7.DataModel.Classes.TestTemplate;
using DTS.Common;
using DTS.Common.Classes.CustomerDetails;
using DTS.Common.Classes.Groups;
using DTS.Common.Classes.Groups.ChannelSettings;
using DTS.Common.Classes.Hardware;
using DTS.Common.Classes.LabratoryDetails;
using DTS.Common.Classes.Sensors;
using DTS.Common.Classes.TestEngineerDetails;
using DTS.Common.Classes.TestSetups;
using DTS.Common.Converters;
using DTS.Common.Enums;
using DTS.Common.Enums.DASFactory;
using DTS.Common.Enums.Hardware;
using DTS.Common.Enums.Sensors;
using DTS.Common.Enums.TestSetups;
using DTS.Common.Events;
using DTS.Common.Interface.Channels;
using DTS.Common.Interface.DASFactory;
using DTS.Common.Interface.DASFactory.Diagnostics;
using DTS.Common.Interface.DataRecorders;
using DTS.Common.Interface.Groups;
using DTS.Common.Interface.Groups.GroupList;
using DTS.Common.Interface.ISO.ExtraProperties;
using DTS.Common.Interface.RegionOfInterest;
using DTS.Common.Interface.Sensors;
using DTS.Common.Interface.TestSetups;
using DTS.Common.Interface.TestSetups.TestSetupsList;
using DTS.Common.ISO;
using DTS.Common.Storage;
using DTS.Common.Utilities;
using DTS.Common.Utilities.Logging;
using DTS.Common.Utils;
using DTS.SensorDB;
using DTS.Slice.Users.UserSettings;
using ISO;
using Prism.Ioc;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows;
using IGroupChannel = DTS.Common.Interface.Channels.IGroupChannel;
using DTS.Common.SharedResource.Strings;
using DTS.Common.DataModel;
using DTS.Common.Licensing;
using DTS.Common.DataModel.Common.DbWrappers;
using DTS.Common.DataModel.Common;
using DTS.Common.Classes.DSP;
using Prism.Events;
using Unity;
using DTS.Common.Classes.Sensors.StreamOut;
using DTS.Common.Constant.DASSpecific;
namespace DataPROWin7.DataModel
{
public class TestTemplate : TestTemplateBase, IComparable<TestTemplate>, ICachedContainer, ITestTemplate
{
/// <summary>
/// returns true if device is a S6A or S6A-BR
/// </summary>
/// <param name="hType"></param>
/// <returns></returns>
private static bool IsASlice6AirType(HardwareTypes hType)
{
return hType == HardwareTypes.SLICE6_AIR || hType == HardwareTypes.SLICE6_AIR_BR;
}
/// <summary>
/// returns true if the test setup has meaningful pre trigger time
/// </summary>
public bool HasPreTrigger
{
get
{
if (RecordingMode == RecordingModes.Active && StartWithEvent)
{
return false;
}
if (DoStreaming) { return false; }
return RecordingModeExtensions.IsACircularBufferMode(RecordingMode);
}
}
/// <summary>
/// returns true if level triggers are disabled because of the recording mode for test
/// http://manuscript.dts.local/f/cases/edit/26963/Incorrect-TSR-AIR-Arm-step-displays-when-Start-recording-with-event-line-is-checked
/// </summary>
public bool LevelTriggersDisabled
{
get
{
if (RecordingMode == RecordingModes.Scheduled) { return true; }
if (RecordingMode == RecordingModes.Interval) { return true; }
if (StartWithEvent) { return true; }
return false;
}
}
/// <summary>
/// adjusts the channels available in test for any TSR AIR based on recording rate
/// </summary>
public void FixTSRAIRChannelsForSpeed(DASHardware h, bool forceChanges = false)
{
if (null == h) { return; }
if (!h.IsTSRAIR()) { return; }
var rate = GetSampleRateForHardware(h);
if (rate <= DFConstantsAndEnums.TSR_AIR_HIGH_G_CUTOFF_RATE_SPS)
{
RemoveHighGChannels(h);
}
else
{
AddHighGChannels(h, forceChanges);
}
}
private readonly List<string> previousHiGChannels = new List<string>();
/// <summary>
/// removes any High g channels for hardware from test (if present)
/// </summary>
private void RemoveHighGChannels(DASHardware h)
{
var channels = GetChannels();
var channelsToRemove = new List<IGroupChannel>();
foreach (var ch in channels)
{
if (ch.DASId != h.DASId) { continue; }
if (null == ch.HardwareChannel) { continue; }
if (SensorConstants.IsTSRAirHighGChannel(ch.HardwareChannel.ModuleSerialNumber))
{
//30144 3) High G channels should not appear in the Channel List table after changing
// the Sample Rate from <= 500 to > 500 if they were not part of the Test Setup previously.
previousHiGChannels.Add(ch.HardwareChannel.ToString());
channelsToRemove.Add(ch);
}
}
if (channelsToRemove.Any())
{
var group = channelsToRemove.Select(ch => ch.Group).FirstOrDefault();
var groupChannels = ChannelsForGroup[group].ToList();
foreach (var ch in channelsToRemove)
{
groupChannels.Remove(ch);
}
ChannelsForGroup[group] = groupChannels.ToArray();
}
var allChannels = GetChannels();
}
/// <summary>
/// adds High g channels for hardware to test (if not present)
/// </summary>
private void AddHighGChannels(DASHardware h, bool forceChanges = false)
{
var channels = GetChannels();
var dontNeedToAdd = channels.Exists(ch => ch.DASId == h.DASId && null != ch.HardwareChannel && SensorConstants.IsTSRAirHighGChannel(ch.HardwareChannel.ModuleSerialNumber));
if (dontNeedToAdd) { return; }
var group = channels.Find(ch => ch.DASId == h.DASId).Group;
var channelsForGroup = ChannelsForGroup[group].ToList();
var insertPoint = 3;
var lowGForDAS = from ch in channelsForGroup
where ch.DASId == h.DASId && null != ch.HardwareChannel &&
SensorConstants.IsTSRAirLowGChannel(ch.HardwareChannel.ModuleSerialNumber)
select ch;
if (null != lowGForDAS && lowGForDAS.Any())
{
insertPoint = 1 + lowGForDAS.Max(ch => channelsForGroup.IndexOf(ch));
}
var defaults = DbOperations.GetChannelSettingDefaults();
var analog = DTS.SensorDB.SensorsCollection.SensorsList.GetSensorBySerialNumber(SensorConstants.TEST_SPECIFIC_ANALOG_SERIAL);
foreach (var ch in h.Channels)
{
//30144 3) High G channels should not appear in the Channel List table after changing
// the Sample Rate from <= 500 to > 500 if they were not part of the Test Setup previously.
if (SensorConstants.IsTSRAirHighGChannel(ch.ModuleSerialNumber) && (previousHiGChannels.Contains(ch.ToString()) || forceChanges))
{
channelsForGroup.Insert(insertPoint, GroupChannel.CreateTSRAirChannel(ch, group, analog, defaults));
previousHiGChannels.Remove(ch.ToString());
insertPoint++;
}
}
var start = channelsForGroup[0].TestSetupOrder;
for (var i = 1; i < channelsForGroup.Count; i++)
{
channelsForGroup[i].TestSetupOrder = ++start;
}
ChannelsForGroup[group] = channelsForGroup.ToArray();
}
/// <summary>
/// stores a mapping of group channel objects for a given calculated channel, this lets us then go and update the ids
/// for that calculated channel once we have ids for the channelsa
/// </summary>
private Tuple<CalculatedValueClass, IGroupChannel[]>[] _calculatedChannelMappings = new Tuple<CalculatedValueClass, IGroupChannel[]>[0];
/// <summary>
/// updates the mapping of a calculated channel to group channels that make up the input channels, this is so the information can be used
/// to update the input channel ids for the calculated channel during commit time
/// 28099 Exporting test setup does not export calculated channels
/// we set these mappings just prior to committing
/// </summary>
/// <param name="mappings"></param>
public void AddCalculatedChannelMappings(Tuple<CalculatedValueClass, IGroupChannel[]>[] mappings)
{
_calculatedChannelMappings = mappings;
}
/// <summary>
/// removes any mappings of calculated channels to group channels that make up the input channels
/// we do this just for safety and to reduce the amount of items we are holding onto
/// we remove the mappings after we are finished commiting a test setup
/// </summary>
public void ClearCalculatedChannelMappings()
{
_calculatedChannelMappings = new Tuple<CalculatedValueClass, IGroupChannel[]>[0];
}
/// <summary>
/// fixes the input channel ids for any calculated channels in the test setup using a list of group channels for
/// each calculated channel
/// 28099 Exporting test setup does not export calculated channels
/// </summary>
public void UpdateCalculatedChannelInputIds()
{
if (null == _calculatedChannelMappings || 0 == _calculatedChannelMappings.Length) { return; }
foreach (var cc in CalculatedChannels)
{
var match = _calculatedChannelMappings.FirstOrDefault(map => map.Item1 == cc);
if (null == match) { continue; }
var channelIds = new List<string>();
foreach (var channel in match.Item2)
{
channelIds.Add(channel.Id.ToString());
}
cc.InputChannelIds = channelIds.ToArray();
}
}
/// <summary>
/// removes the ids for this test template creating a copy without the id associations
/// </summary>
public void CreateCopy()
{
//13565 All channels removed from test (created by using copy) after I modified a sensor
//it was using the same group and channels for both test setups
//we have to force it to create new test setups.
UpdateFromDb();
Id = -1;
foreach (var group in Groups)
{
group.Id = -1;
group.Name = Guid.NewGuid().ToString();
}
var channels = GetChannels();
var oldChannelIdToChannel = new Dictionary<long, IGroupChannel>();
var channelIndex = -1;
foreach (var ch in channels)
{
oldChannelIdToChannel[ch.Id] = ch;
ch.Id = channelIndex--;
}
foreach (var cc in CalculatedChannels)
{
var inputChannels = new List<IGroupChannel>();
foreach (var sid in cc.InputChannelIds)
{
if (long.TryParse(sid, out var l) && oldChannelIdToChannel.ContainsKey(l))
{
inputChannels.Add(oldChannelIdToChannel[l]);
}
}
cc.InputChannelIds = new string[0];
cc.SetChannels(inputChannels.ToArray());
}
using (var enumLevelTriggers = LevelTriggerChannels.GetEnumerator())
{
while (enumLevelTriggers.MoveNext())
{
var lt = enumLevelTriggers.Current.Value;
if (long.TryParse(lt.GroupChannelId, out var l) && oldChannelIdToChannel.ContainsKey(l))
{
lt.GroupChannelId = "";
lt.GroupChannel = oldChannelIdToChannel[l];
}
}
}
}
//warnings that are ok for saving, but not running tests
//FB 14623 Added EditTestSetupParameters_EmptySquibDelay to incomplete warnings list
public static readonly string[] _incompleteWarnings = new[]
{
StringResources.EditTestSetupPageError_MissingSensor,
StringResources.EditTestSetupParameters_EmptySquibDelay,
StringResources.EditTestSetup_TTSUserValue2,
StringResources.EditTestSetupPage_NoPhysicalHardwareInTest//,
//StringResources.EditTestSetupPage_AAFilterRateOutOfRange
};
private List<DASHardware> _hardware = null;
private List<DASHardware> _nonDistributorHardware = null;
private static readonly object HardwareLock = new object();
public void ClearHardware()
{
lock (HardwareLock)
{
_hardware = null;
}
}
public void AddHardwareToMemory(DASHardware hardware)
{
lock (HardwareLock)
{
if (null == _hardware)
{
return;
}
var matches = from h in _hardware where h.DASId == hardware.DASId select h;
if (!matches.Any())
{
_hardware.Add(hardware);
}
}
}
public void RemoveHardwareFromMemory(DASHardware hardware)
{
lock (HardwareLock)
{
if (null == _hardware) { return; }
var matches = from h in _hardware where h.DASId == hardware.DASId select h;
if (matches.Any())
{
foreach (var match in matches)
{
_hardware.Remove(match);
}
}
}
}
public static void ValidateHardware(DASHardware h, bool warningsOnly, ref List<string> warnings, ref List<string> errors)
{
if (h.CalDateFailed && !h.IsTSRAIR())
{
//Past the calibration date (overdue)
if (SerializedSettings.CalHWPolicy == SerializedSettings.OVERDUE_HARDWARE_POLICIES.ALLOW_ALWAYS)
{
//Always allow the hardware to be used, but warn that the hardware is past the calibration date
CultureInfo germanCulture = new CultureInfo("de-DE");
CultureInfo.CurrentCulture = germanCulture;
var fDate = h.CalDueDate.Date.ToShortDateString();
//warnings.Add(string.Format(StringResources.EditObjectPageWarning_HardwareCalDateOverdue, h.SerialNumber, h.CalDueDate.ToShortDateString()));
warnings.Add(string.Format(StringResources.EditObjectPageWarning_HardwareCalDateOverdue, h.SerialNumber, fDate));
}
else if (SerializedSettings.CalHWPolicy == SerializedSettings.OVERDUE_HARDWARE_POLICIES.ALLOW_UPTO_GRACE_PERIOD)
{
//Only allow the hardware to be used if we're still within the grace period
if (h.CalDueDate.AddDays(SerializedSettings.CalHWGracePeriodDays) < DateTime.Now.Date)
{
//We're outside of the grace period, so we don't want to allow the overdue hardware to be used, but we want to only return a warning here when called
//from the page, not an error, so that the Test Setup will be saved but incomplete. An error will be returned when the TestTemplate is validated.
if (warningsOnly)
{
warnings.Add(string.Format(StringResources.EditObjectPageWarning_HardwareCalDateOverdue, h.SerialNumber, h.CalDueDate.ToShortDateString()));
}
else
{
errors.Add(string.Format(StringResources.EditObjectPageError_HardwareCalDateOverdue, h.SerialNumber, h.CalDueDate.ToShortDateString()));
}
}
else
{
//We're still in the grace period, so just display a warning
warnings.Add(string.Format(StringResources.EditObjectPageWarning_HardwareCalDateOverdue, h.SerialNumber, h.CalDueDate.ToShortDateString()));
}
}
else
{
//The policy must be DONT_ALLOW, so we don't want to allow the overdue hardware to be used, but we want to only return a warning here when called
//from the page, not an error, so that the Test Setup will be saved but incomplete. An error will be returned when the TestTemplate is validated.
if (warningsOnly)
{
warnings.Add(string.Format(StringResources.EditObjectPageWarning_HardwareCalDateOverdue, h.SerialNumber, h.CalDueDate.ToShortDateString()));
}
else
{
errors.Add(string.Format(StringResources.EditObjectPageError_HardwareCalDateOverdue, h.SerialNumber, h.CalDueDate.ToShortDateString()));
}
}
}
else if (h.CalDateWarning && !h.IsTSRAIR())
{
//Not past the calibration date, but past the warning date, so warn
warnings.Add(string.Format(StringResources.EditObjectPageWarning_HardwareCalDateOverdue, h.SerialNumber, h.CalDueDate.ToShortDateString()));
}
}
/// <summary>
/// written as part of issue
/// 15395 Download tile using wrong DAS when browsing to DTS file
/// this function sets the test hardware so that it won't be required from the db
/// it's currently only intended for emergency download, it's probably ok to use outside
/// of that, but it was designed for a narrow use
/// </summary>
/// <param name="hardwares"></param>
public void SetHardware(DASHardware[] hardwares)
{
lock (HardwareLock)
{
_hardware = new List<DASHardware>();
foreach (var h in hardwares)
{
_hardware.Add(new DASHardware(h.GetHardware()));
}
}
}
/// <summary>
/// MS 31861 detected where the hardware list for a test setup could have extra das in it based on
/// stable groups having different hardware than embedded groups
/// This function just corrects the current list to only look at what is in the
/// IncludedHardware list
/// </summary>
public void CorrectHardwareList()
{
lock (HardwareLock)
{
if (null != _hardware)
{
var hardware = _hardware.ToArray();
var ids = GetAllIncludedHardware();
foreach (var h in hardware)
{
if (!ids.Contains(h.DASId)) { _hardware.Remove(h); }
}
}
}
}
public DASHardware[] GetHardware()
{
lock (HardwareLock)
{
if (null == _hardware)
{
var allHardware = DASHardwareList.GetAllHardware();
var lookup = new Dictionary<int, Hardware>();
foreach (var h in allHardware) { lookup[h.DASId] = h.GetHardware(); }
var included = new HashSet<int>();
var l = new List<DASHardware>();
foreach (var hid in GetAllIncludedHardware())
{
if (included.Contains(hid))
{
continue;
}
if (lookup.ContainsKey(hid))
{
included.Add(hid);
l.Add(new DASHardware(lookup[hid]));
}
}
_hardware = l;
}
}
return _hardware.ToArray();
}
public DASHardware[] GetNonDistributorHardware()
{
lock (HardwareLock)
{
if (null == _nonDistributorHardware)
{
GetHardware();
_nonDistributorHardware = new List<DASHardware>();
foreach (var das in _hardware)
{
if (das.IsNonDistributorHardware)//temp
{
_nonDistributorHardware.Add(das);
}
}
}
}
return _nonDistributorHardware.ToArray();
}
#region var and const
public List<CalculatedValueClass> CalculatedChannels = new List<CalculatedValueClass>();
private readonly List<string> _channelKeysInOrder = new List<string>();
private readonly List<HardwareChannel> _hardwareChannelsInOrder = new List<HardwareChannel>();
/// <summary>
/// dictionary of harware overrides for the test
/// key is hardware id
/// if present, then value is whether the hardware is included or removed from the test.
/// </summary>
public Dictionary<string, HardwareInclusionInstruction> HardwareOverrides = new Dictionary<string, HardwareInclusionInstruction>();
/// <summary>
/// cache of sensors for the test setup
/// this keeps us from having to lookup sensors and apply changes every time we need to use them
/// </summary>
public Dictionary<string, Dictionary<string, Dictionary<string, SensorData>>> SensorLookup = new Dictionary<string, Dictionary<string, Dictionary<string, SensorData>>>();
private static readonly object HardwareChannelLookupLock = new object();
private Dictionary<int, HardwareChannel> _absoluteNumberToHardwareChannel;
private Dictionary<string, int> _dasChannelNumberToAbsoluteNumber;
public new bool ViewRealtime
{
get => 0 != GetNumberOfRealtimeSupportedChannels() && base.ViewRealtime;
set => base.ViewRealtime = value;
}
#endregion var and const
#region Constructor
public TestTemplate(TestSetupDefaults settings = null,
bool bLoaded = true,
SimpleHardware[] hardware = null,
ITestSetupRecord copy = null)
{
_downloadFolder = DataModelSettings.DownloadFolder;
_exportFolder = DataModelSettings.DownloadFolder;
_defaultDownloadFolder = DataModelSettings.DownloadFolder;
InitializeFromDefaults(settings, hardware);
_bIsLoaded = bLoaded;
if (null != copy)
{
Copy(copy);
}
LoadSettings(Settings);
}
public static int GetDefaultNumberOfRealtimeGraphs(RealtimeGraphsEnum realtimeGraphs)
{
switch (realtimeGraphs)
{
case RealtimeGraphsEnum.One: return 1;
case RealtimeGraphsEnum.Three: return 3;
case RealtimeGraphsEnum.Six:
default:
return 6;
}
}
//gets all the hardware in the db in simple form (serial/parentdas/dasid)
public static SimpleHardware[] GetSimpleHardwares()
{
List<SimpleHardware> list = new List<SimpleHardware>();
using (var cmd = DbOperations.GetSQLCommand(true))
{
try
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT [DASId], [SerialNumber], [ParentDAS], [Type] FROM [DAS] WHERE [Position] != 'Prototype'";
var reader = cmd.ExecuteReader();
while (reader.Read())
{
int dasId = Convert.ToInt32(reader["DASId"]);
var serialNumber = (string)reader["SerialNumber"];
var o = reader["ParentDAS"];
var parentDAS = DBNull.Value.Equals(o) ? "" : (string)o;
list.Add(new SimpleHardware(serialNumber, parentDAS, dasId, Convert.ToInt32(reader["Type"])));
}
}
finally
{
cmd.Connection.Dispose();
}
}
return list.ToArray();
}
public Dictionary<IGroup, IGroupChannel[]> ChannelsForGroup { get; set; } = new Dictionary<IGroup, IGroupChannel[]>();
public Dictionary<string, bool> DASClockMasterList { get; set; } = new Dictionary<string, bool>(200);
public Dictionary<string, double> DASSampleRateList { get; set; } = new Dictionary<string, double>(200);
public Dictionary<string, float> DASAAFRateList { get; set; } = new Dictionary<string, float>();
public Dictionary<string, int> DASSamplesPerPacketList { get; set; } = new Dictionary<string, int>();
public Dictionary<string, byte> DASPTPDomainIDList { get; set; } = new Dictionary<string, byte>();
public Dictionary<string, List<string>> EncapsulatedDASList { get; set; } = new Dictionary<string, List<string>>(200);
public Dictionary<IGroupChannel, IChannelSetting[]> ChannelSettingsForChannel { get; set; } =
new Dictionary<IGroupChannel, IChannelSetting[]>(200);
public double GetSampleRate(string dasSerialNumber, double defaultValue)
{
if (!DASSampleRateList.ContainsKey(dasSerialNumber))
{
DASSampleRateList[dasSerialNumber] = defaultValue;
}
return DASSampleRateList[dasSerialNumber];
}
public double GetNextHighestAvailableSampleRate(string serialNumber, List<double> availableSampleRates)
{
return GetNextHighestAvailableSampleRate(serialNumber, availableSampleRates, DASSampleRateList, DASAAFRateList);
}
public static double GetNextHighestAvailableSampleRate(string serialNumber, List<double> availableSampleRates, Dictionary<string, double> dasSampleRateList, Dictionary<string, float> dasAAFRateList)
{
var requestedRate = dasSampleRateList[serialNumber];
var hardware = DASHardwareList.GetList().GetHardware(serialNumber);
foreach (var sampleRate in availableSampleRates)
{
dasSampleRateList[serialNumber] = sampleRate;
dasAAFRateList[serialNumber] = GetAAFForHardware(hardware, (int)sampleRate);
if (sampleRate > requestedRate)
{
break;
}
}
return dasSampleRateList[serialNumber];
}
public Visibility TooltipVisibility
{
get
{
//calculating is complete can be expensive when you have a large list of test setups
//for immediate time just disable this feature
return Visibility.Collapsed;
}
}
public string TooltipMessage => CompletionErrorMessage;
public new double PreTriggerSeconds
{
get
{
return RecordingModeExtensions.CanProgramPreTrigger(RecordingMode) ? base.PreTriggerSeconds : 0D;
}
set => base.PreTriggerSeconds = value;
}
private void InitializeFromDefaults(TestSetupDefaults settingsParam = null, SimpleHardware[] hardware = null)
{
var settings = settingsParam ?? TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id);
_settings = CreateSettingsDictionary(settings);
SuppressMissingSensorsWarning = settings.DefaultSuppressMissingSensorsWarning;
CalibrationBehavior = settings.DefaultSensorCalibrationBehavior;
RecordingMode = settings.AllowTSRAIRRecordingModes ? RecordingModes.Active : settings.DefaultRecordingMode;
PreTriggerSeconds = settings.DefaultPreTriggerSeconds;
PostTriggerSeconds = settings.DefaultPostTriggerSeconds;
NumberOfEvents = settings.DefaultNumberOfEvents;
IsComplete = false;
RecordingMode = settings.DefaultRecordingMode;
UploadFolder = settings.DefaultUploadFolder;
AllowMissingSensors = settings.DefaultAllowMissingSensors;
AllowSensorIdToBlankChannel = !settings.DefaultRequireSensorIdFound;
ArmCheckListStep = settings.DefaultArmCheckListStep;
AutomaticProgression = settings.DefaultAutomaticMode;
AutomaticProgressionDelayMS = Convert.ToInt32(settings.DefaultTestSetupAutomaticProgressDelaySeconds * 1000D);
CalibrationBehavior = settings.DefaultSensorCalibrationBehavior;
CheckListBatteryVoltageCheck = settings.DefaultCheckListBatteryVoltageCheck;
CheckListInputVoltageCheck = settings.DefaultCheckListInputVoltageCheck;
CheckListRequirePass = settings.DefaultChecklistMustPass;
CheckListSensorIdCheck = settings.DefaultCheckListSensorIdCheck;
CheckListSquibResistanceCheck = settings.DefaultCheckListSquibResistanceCheck;
CheckListTriggerStartCheck = settings.DefaultCheckListTriggerStartCheck;
CheckListTiltSensorCheck = settings.DefaultCheckListTiltSensorCheck;
CheckListTemperatureCheck = settings.DefaultCheckListTemperatureCheck;
DownloadAll = settings.DefaultDownloadAll;
DoROIDownload = settings.DefaultDownloadROI;
ExcitationWarmupTimeMS = Convert.ToInt32(settings.DefaultTestExcitationWarmupSeconds * 1000D);
DefaultNumberRealtimeGraphs = GetDefaultNumberOfRealtimeGraphs(settings.DefaultRealtimeGraphCount);
StrictDiagnostics = settings.DefaultRequireAllUnitsPassDiagnostics;
RequireUserConfirmationOnErrors = settings.DefaultRequireUserConfirmationOnErrors;
RegionsOfInterest = new BindingList<IRegionOfInterest> { new RegionOfInterest("", true, settings.DefaultROIStart, settings.DefaultROIEnd) };
ROIEnd = settings.DefaultROIEnd;
ROIStart = settings.DefaultROIStart;
PostTestDiagnosticsLevel = settings.DefaultRunPostTestDiagnostics;
SamplesPerSecondAggregate = settings.DefaultTestSampleRate;
if (null == hardware) { hardware = GetSimpleHardwares(); }
foreach (var das in hardware)
{
DASClockMasterList[das.SerialNumber] = false;
DASSampleRateList[das.SerialNumber] = settings.DefaultTestSampleRate;
DASAAFRateList[das.SerialNumber] = GetAAFForHardware(das, (int)settings.DefaultTestSampleRate);
DASSamplesPerPacketList[das.SerialNumber] = GetSamplesPerPacketForHardware((int)settings.DefaultTestSampleRate);
DASPTPDomainIDList[das.SerialNumber] = settings.DefaultPTPDomainID;
if (!string.IsNullOrWhiteSpace(das.ParentDAS))
{
var childList = new List<string>();
//This is a child
if (EncapsulatedDASList.ContainsKey(das.ParentDAS))
{
childList = EncapsulatedDASList[das.ParentDAS];
}
childList.Add(das.SerialNumber);
EncapsulatedDASList[das.ParentDAS] = childList;
}
}
TriggerCheckStep = settings.DefaultTriggerCheckStep;
ViewDownloadAll = settings.DefaultViewAll;
ViewROIDownload = settings.DefaultViewROI;
MeasureSquibResistancesStep = settings.DefaultMeasureSquibResistancesStep;
if (settings.ExportChryslerDDAS) { ExportFormats |= SupportedExportFormatBitFlags.ChryslerDDAS; }
if (settings.ExportCSVFiltered) { ExportFormats |= SupportedExportFormatBitFlags.csvfiltered; }
if (settings.ExportCSVUnfiltered) { ExportFormats |= SupportedExportFormatBitFlags.csvunfiltered; }
if (settings.ExportCSVADC) { ExportFormats |= SupportedExportFormatBitFlags.CSVADC; }
if (settings.ExportCSVMV) { ExportFormats |= SupportedExportFormatBitFlags.CSVMV; }
if (settings.ExportHDFADC) { ExportFormats |= SupportedExportFormatBitFlags.HDFADC; }
if (settings.ExportHDFFiltered) { ExportFormats |= SupportedExportFormatBitFlags.HDFFiltered; }
if (settings.ExportHDFMV) { ExportFormats |= SupportedExportFormatBitFlags.HDFMV; }
if (settings.ExportHDFUnfiltered) { ExportFormats |= SupportedExportFormatBitFlags.HDFUnfiltered; }
if (settings.ExportISOFiltered) { ExportFormats |= SupportedExportFormatBitFlags.isofiltered; }
if (settings.ExportISOUnFiltered) { ExportFormats |= SupportedExportFormatBitFlags.isounfiltered; }
if (settings.ExportRDFADC) { ExportFormats |= SupportedExportFormatBitFlags.rdfadc; }
if (settings.ExportSomatFiltered) { ExportFormats |= SupportedExportFormatBitFlags.somatfiltered; }
if (settings.ExportSomatUnfiltered) { ExportFormats |= SupportedExportFormatBitFlags.somatunfiltered; }
if (settings.ExportTDASADC) { ExportFormats |= SupportedExportFormatBitFlags.tdasadc; }
if (settings.ExportTDMSADC) { ExportFormats |= SupportedExportFormatBitFlags.tdmsadc; }
if (settings.ExportToyotaFiltered) { ExportFormats |= SupportedExportFormatBitFlags.toyotafiltered; }
if (settings.ExportToyotaUnfiltered) { ExportFormats |= SupportedExportFormatBitFlags.toyotaunfiltered; }
if (settings.ExportTSVFiltered) { ExportFormats |= SupportedExportFormatBitFlags.tsvfiltered; }
if (settings.ExportTSVUnfiltered) { ExportFormats |= SupportedExportFormatBitFlags.tsvunfiltered; }
if (settings.ExportXLSXFiltered) { ExportFormats |= SupportedExportFormatBitFlags.xlsxfiltered; }
if (settings.ExportXLSXUnfiltered) { ExportFormats |= SupportedExportFormatBitFlags.xlsxunfiltered; }
if (settings.ExportDiademADC) { ExportFormats |= SupportedExportFormatBitFlags.diademadc; }
if (settings.ExportASC) { ExportFormats |= SupportedExportFormatBitFlags.FIATASC; }
//CheckoutMode = settings.DefaultCheckoutMode;
QuitTestWithoutWarning = settings.SupressQuitTestWarning;
NotAllChannelsRealTime = settings.SuppressViewAllRealtime;
NotAllChannelsViewer = settings.SupressViewAllViewer;
CommonLine = settings.DefaultCommonStatusLine;
WarnOnFailedBattery = settings.DefaultWarnOnFailedBattery;
IgnoreShortedStartCompletion = settings.DefaultIgnoreShortedStart;
IgnoreShortedTriggerCompletion = settings.DefaultIgnoreShortedTrigger;
//17577 AutoArm Remove Auto-Arm from config file
DoAutoArm = /* Properties.Settings.Default.Allow &&*/ settings.DefaultAutoArm;
DoStreaming = settings.AllowStreamingModes && settings.DefaultStreaming;
DoEnableRepeat = settings.DefaultAutoArmRepeatEnable;
ClockSyncProfileMaster = settings.DefaultClockSyncProfileMaster;
ClockSyncProfileSlave = settings.DefaultClockSyncProfileSlave;
UploadData = settings.DefaultUploadEnabled;
UploadExportsOnly = settings.DefaultUploadExportsOnly;
ViewExport = settings.DefaultExport;
ViewRealtime = settings.DefaultViewRealtime;
IntervalBetweenEventStartsMinutes = settings.DefaultIntervalBetweenEventStartsMinutes;
RTCScheduleStartDateTime = DateTime.UtcNow;
AlignUDPToPPS = settings.AlignUDPToPPS;
ExtraProperties = new List<IExtraProperty>();
}
// FB14276: Add Custom ISO Key-Value Pairs
public TestTemplate(bool NotUsed)
{
_downloadFolder = DataModelSettings.DownloadFolder;
_exportFolder = DataModelSettings.DownloadFolder;
_defaultDownloadFolder = DataModelSettings.DownloadFolder;
InitializeFromDefaults();
ExpressTestSetup = true;
Name = StringResources.TestTemplate_ExpressTestSetup;
}
private void OldTestTemplateLiteCopy(TestTemplate copy)
{
Id = copy.Id;
foreach (var g in copy.Groups)
{
Groups.Add(g);
}
ChannelsForGroup = copy.ChannelsForGroup;
AddedHardware = copy.AddedHardware;
RemovedHardware = copy.RemovedHardware;
DASSampleRateList = new Dictionary<string, double>();
using (var e = copy.DASSampleRateList.GetEnumerator())
{
while (e.MoveNext())
{
DASSampleRateList[e.Current.Key] = e.Current.Value;
}
}
_dasSettings.Clear();
using (var e = copy._dasSettings.GetEnumerator())
{
while (e.MoveNext())
{
_dasSettings[e.Current.Key] = new DASSettings(e.Current.Value);
}
}
DASAAFRateList = copy.DASAAFRateList;
DASSamplesPerPacketList = copy.DASSamplesPerPacketList;
DASClockMasterList = copy.DASClockMasterList;
DASPTPDomainIDList = copy.DASPTPDomainIDList;
}
public bool Filter(string term)
{
if (string.IsNullOrWhiteSpace(term)) { return true; }
term = term.ToLower();
if (Name.ToLower().Contains(term)) { return true; }
if (Description.ToLower().Contains(term)) { return true; }
if (LastModifiedBy.ToLower().Contains(term)) { return true; }
return false;
}
public void AddGroup(IGroup group, IDictionary<int, ISensorData> sensorLookup, IDictionary<int, IDASHardware> hardwareLookup, IChannelSetting[] channelDefaults)
{
if (Groups.Any(g => g.Id == group.Id && group.Id >= 0)) { return; }
Groups.Add(group);
OnPropertyChanged("Groups");
var allChannels = group.GetAllChannels(true, sensorLookup, hardwareLookup, channelDefaults, SerializedSettings.AllowSensorPushAndPull);
group.DeterminePositionAndTestObject(allChannels);
ChannelsForGroup[group] = allChannels;
}
public void AddGroup(IGroup group, IDictionary<int, ISensorData> sensorLookup, IDictionary<long, IGroupChannel> channelLookup)
{
if (Groups.Any(g => g.Id == group.Id && group.Id >= 0)) { return; }
Groups.Add(group);
OnPropertyChanged("Groups");
var allChannels = new List<IGroupChannel>();
foreach (var channel in channelLookup)
{
channel.Value.Group = group;
allChannels.Add(channel.Value);
}
group.DeterminePositionAndTestObject(allChannels.ToArray());
ChannelsForGroup[group] = allChannels.ToArray();
}
public int[] AddedHardware { get; set; } = new int[0];
public int[] RemovedHardware { get; set; } = new int[0];
public int[] GetAllIncludedHardware()
{
var list = new List<int>();
foreach (var group in Groups)
{
foreach (var id in group.IncludedHardware)
{
if (!list.Contains(id))
{
list.Add(id);
}
}
}
foreach (var id in AddedHardware)
{
if (!list.Contains(id))
{
list.Add(id);
}
}
foreach (var id in RemovedHardware)
{
if (list.Contains(id))
{
list.Remove(id);
}
}
return list.ToArray();
}
public void AddHardware(int dasId)
{
if (RemovedHardware.Contains(dasId))
{
var list = RemovedHardware.ToList();
list.Remove(dasId);
RemovedHardware = list.ToArray();
}
var newList = AddedHardware.ToList();
if (!newList.Contains(dasId))
{
newList.Add(dasId);
AddedHardware = newList.ToArray();
}
}
public void AddHardware(int dasId, string dasSerialNumber, IDASHardware[] allHardware, IDictionary<int, IDASHardware> lookup)
{
DASHardware hw = null;
if (lookup.ContainsKey(dasId))
{
hw = (DASHardware)lookup[dasId];
}
if (RemovedHardware.Contains(dasId))
{
var list = RemovedHardware.ToList();
list.Remove(dasId);
if (null != hw && hw.IsTSRAIR())
{
var moduleIdList = DASHardwareList.GetEmbeddedModules(allHardware, hw.DASId);
foreach (var moduleId in moduleIdList)
{
list.Remove(moduleId);
}
}
RemovedHardware = list.ToArray();
}
var newList = AddedHardware.ToList();
if (!newList.Contains(dasId))
{
newList.Add(dasId);
if (null != hw && hw.IsTSRAIR())
{
var moduleIdList = DASHardwareList.GetEmbeddedModules(allHardware, hw.DASId);
foreach (var moduleId in moduleIdList)
{
newList.Add(moduleId);
}
}
AddedHardware = newList.ToArray();
}
}
public void AddHardware(int dasId, IDictionary<int, IDASHardware> lookup)
{
DASHardware hw = null;
if (lookup.ContainsKey(dasId))
{
hw = (DASHardware)lookup[dasId];
}
if (null == hw)
{
hw = DASHardwareList.GetList().GetHardware(dasId);
}
var allHardware = lookup.Values.ToArray();
if (RemovedHardware.Contains(dasId))
{
var list = RemovedHardware.ToList();
list.Remove(dasId);
if (hw != null && hw.IsTSRAIR())
{
//var hardwareArray = DASHardwareList.GetAllHardware();
var moduleIdList = DASHardwareList.GetEmbeddedModules(allHardware, hw.DASId);
foreach (var moduleId in moduleIdList)
{
list.Remove(moduleId);
}
}
RemovedHardware = list.ToArray();
}
var newList = AddedHardware.ToList();
if (!newList.Contains(dasId))
{
newList.Add(dasId);
if (hw != null && hw.IsTSRAIR())
{
//var hardwareArray = DASHardwareList.GetAllHardware();
var moduleIdList = DASHardwareList.GetEmbeddedModules(allHardware, hw.DASId);
foreach (var moduleId in moduleIdList)
{
newList.Add(moduleId);
}
}
AddedHardware = newList.ToArray();
}
}
public void RemoveHardware(int dasId, IDASHardware[] allHardware, IDictionary<int, IDASHardware> lookup)
{
DASHardware hw = null;
if (lookup.ContainsKey(dasId))
{
hw = (DASHardware)lookup[dasId];
}
if (AddedHardware.Contains(dasId))
{
var list = AddedHardware.ToList();
list.Remove(dasId);
if (null != hw && hw.IsTSRAIR())
{
var moduleIdList = DASHardwareList.GetEmbeddedModules(allHardware, hw.DASId);
foreach (var moduleId in moduleIdList)
{
list.Remove(moduleId);
}
}
AddedHardware = list.ToArray();
}
var newList = RemovedHardware.ToList();
if (!newList.Contains(dasId))
{
newList.Add(dasId);
}
if (null != hw && hw.IsTSRAIR())
{
var moduleIdList = DASHardwareList.GetEmbeddedModules(allHardware, hw.DASId);
foreach (var moduleId in moduleIdList)
{
if (!newList.Contains(moduleId))
{
newList.Add(moduleId);
}
}
}
RemovedHardware = newList.ToArray();
var newChannelsForGroup = new Dictionary<IGroup, IGroupChannel[]>();
using (var eGroups = ChannelsForGroup.GetEnumerator())
{
while (eGroups.MoveNext())
{
var groupChannelList = new List<IGroupChannel>();
foreach (var ch in eGroups.Current.Value)
{
if (ch.DASId == dasId || RemovedHardware.Contains(ch.DASId))
{
//When a TSR AIR or SLICE6 AIR-TC is removed, effectively remove its channels
//from ChannelsForGroup by not adding them to the new list.
if (null != ch.HardwareChannel && !ch.HardwareChannel.IsTSRAIR && !ch.HardwareChannel.IsSLICETC)
{
ch.SetHardwareChannel(null);
groupChannelList.Add(ch);
}
else
{
ch.SetHardwareChannel(null);
}
}
else
{
groupChannelList.Add(ch);
}
}
newChannelsForGroup[eGroups.Current.Key] = groupChannelList.ToArray();
}
}
ChannelsForGroup = newChannelsForGroup;
}
public void SetTestSetupChannelOrder()
{
//When channels are added automatically to the Test channels Group, due to discovering
//DAS with sensor IDs that match the IDs of sensors in the db, their TestSetupOrder
//will not have been set yet, so do it here before calling SaveGroups. FB 17642
var list = new List<IGroupChannel>();
foreach (var group in ChannelsForGroup)
{
foreach (var channel in group.Value)
{
list.Add(channel);
}
}
list.Sort();
for (var i = 0; i < list.Count; i++)
{
list[i].TestSetupOrder = 1 + i;
list[i].CanMoveDown = true;
list[i].CanMoveUp = true;
}
}
public void SaveGroups()
{
//channel id mappings may change when groups are committed, notably for
//groups which aren't in the database yet or channels that aren't in the database yet
//store the old channel id to the group channel so that the new id can be used
var oldChannelIdToGroupChannel = new Dictionary<long, IGroupChannel>();
//step 1, convert any non embedded groups
foreach (var group in Groups)
{
if (group.Embedded) { continue; }
if (!ChannelsForGroup.ContainsKey(group)) { continue; }
group.ConvertToEmbedded(ChannelsForGroup[group]);
}
//step 2, remove any existing groups no longer needed
var groupsToDelete = GetExistingGroupIds().ToList();
//step 3, update any existing groups
var newGroupChannelList = new List<IGroupChannel>();
foreach (var group in Groups)
{
if (group.Id < 0) { continue; }
if (!ChannelsForGroup.ContainsKey(group)) { continue; }
foreach (var channel in ChannelsForGroup[group])
{
oldChannelIdToGroupChannel[channel.Id] = channel;
}
group.Save(ChannelsForGroup[group], ApplicationProperties.CanCurrentUserCommitChannelCodes, ref newGroupChannelList);
groupsToDelete.Remove(group.Id);
UpdateGroupInTestSetup(group);
}
//step 4, insert new groups
foreach (var group in Groups)
{
if (group.Id >= 0) { continue; }
if (!ChannelsForGroup.ContainsKey(group)) { continue; }
foreach (var channel in ChannelsForGroup[group])
{
oldChannelIdToGroupChannel[channel.Id] = channel;
}
group.Save(ChannelsForGroup[group], ApplicationProperties.CanCurrentUserCommitChannelCodes, ref newGroupChannelList);
InsertGroupIntoTest(group);
}
if (newGroupChannelList.Any())
{
ReplaceROIChannels(newGroupChannelList);
}
if (groupsToDelete.Any())
{
DeleteGroupsFromTest(groupsToDelete.ToArray());
}
//now finally, at least for calculated channels replace ids
//28099 Exporting test setup does not export calculated channels
var replacementMapping = new Dictionary<string, string>();
using (var eChannel = oldChannelIdToGroupChannel.GetEnumerator())
{
while (eChannel.MoveNext())
{
if (!eChannel.Current.Key.ToString().Equals(eChannel.Current.Value.Id.ToString()))
{
replacementMapping[eChannel.Current.Key.ToString()] = eChannel.Current.Value.Id.ToString();
}
}
}
if (replacementMapping.Any())
{
ReplaceCalculatedChannel(replacementMapping);
}
}
public void SaveHardware()
{
try
{
var includedHardware = GetAllIncludedHardware();
foreach (var g in Groups)
{
g.IncludedHardware = includedHardware;
}
var hardware = DASHardwareList.GetAllHardware();
var existingHardware = GetExistingHardwareIds();
var addedHardware = AddedHardware;//create a local copy rather than operate on property.
//we shouldn't have a null addedHardware, but we should prep for if we do ...
if (null == addedHardware) { addedHardware = new int[0]; }
foreach (var id in addedHardware)
{
var hardwareRef = Array.Find(hardware, h => h.DASId == id);
if (null == hardwareRef)
{
APILogger.Log($"Hardware id[{id}] has no match in the addedhardware list");
continue;
}
var hardwareSN = hardwareRef.SerialNumber;
// Default to ClockMaster = false unless the module is in the DASClockMasterList
var isClockMaster = false;
if (null != DASClockMasterList &&
DASClockMasterList.ContainsKey(hardwareSN)) { isClockMaster = DASClockMasterList[hardwareSN]; }
var ptpDomainId = TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id).DefaultPTPDomainID;
if (DASPTPDomainIDList.ContainsKey(hardwareSN)) { ptpDomainId = DASPTPDomainIDList[hardwareSN]; }
if (existingHardware.Contains(id))
{
if (!DASSampleRateList.ContainsKey(hardwareSN) || !DASAAFRateList.ContainsKey(hardwareSN) || !DASSamplesPerPacketList.ContainsKey(hardwareSN))
{
APILogger.Log($"Hardware [{hardwareSN}] has no entries in sampleratelist or aafratelist or SamplesPerPacketList");
continue;
}
UpdateExistingHardware(id, 1, DASSampleRateList[hardwareSN], isClockMaster, DASAAFRateList[hardwareSN], ptpDomainId);
}
else
{
if (DASSampleRateList.ContainsKey(hardwareSN) && DASAAFRateList.ContainsKey(hardwareSN) && DASSamplesPerPacketList.ContainsKey(hardwareSN))
{
InsertHardware(id, 1, DASSampleRateList[hardwareSN], isClockMaster, DASAAFRateList[hardwareSN], ptpDomainId);
}
else
{
var hFromDb = Array.Find(hardware, h => h.DASId == id);
if (null == hFromDb)
{
APILogger.Log($"Hardware [{hardwareSN}] has no entry in hardware list");
continue;
}
var defaultAAFRate = GetAAFForHardware(hFromDb,
(int)TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id).DefaultTestSampleRate);
InsertHardware(id, 1, TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id).DefaultTestSampleRate, false, defaultAAFRate, TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id).DefaultPTPDomainID);
}
}
}
var invalidRemovedHardware = new List<int>();
foreach (var id in RemovedHardware)
{
if (existingHardware.Contains(id))
{
// these are hardware that were assigned to the group but are no more
// Is valid hardware in the test
// typical case
UpdateExistingHardware(id, 0, DASSampleRateList[hardware.First(h => h.DASId == id).SerialNumber], DASClockMasterList[hardware.First(h => h.DASId == id).SerialNumber], DASAAFRateList[hardware.First(h => h.DASId == id).SerialNumber], DASPTPDomainIDList[hardware.First(h => h.DASId == id).SerialNumber]);
}
else if (Array.Exists(hardware, h => h.DASId == id))
{
//this shouldn't fail since we just proved there is an entry above ...
//but this is more for convenience of using a short form and not querying for each lookup
var hFromDb = Array.Find(hardware, h => h.DASId == id);
if (null == hFromDb)
{
APILogger.Log($"Hardware [{id}] does not exist in hardware list");
continue;
}
// is hardware that wasn't assigned to the test but is now being explicitly excluded from the test
// Is valid hardware in the db
if (DASSampleRateList.ContainsKey(hFromDb.SerialNumber))
{
if (!DASAAFRateList.ContainsKey(hFromDb.SerialNumber) || !DASClockMasterList.ContainsKey(hFromDb.SerialNumber)
|| !DASAAFRateList.ContainsKey(hFromDb.SerialNumber) || !DASSamplesPerPacketList.ContainsKey(hFromDb.SerialNumber))
{
APILogger.Log($"hardware [{hFromDb.SerialNumber}] doesn't have an entry in either DASAAFRateList or DASClockMasterList or DASAAFRateList or DASSamplesPerPacketList");
continue;
}
InsertHardware(id, 0, DASSampleRateList[hFromDb.SerialNumber], DASClockMasterList[hFromDb.SerialNumber],
DASAAFRateList[hFromDb.SerialNumber], DASPTPDomainIDList[hFromDb.SerialNumber]);
}
else
{
var defaultAAFRate = GetAAFForHardware(hFromDb,
(int)TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id).DefaultTestSampleRate);
InsertHardware(id, 0, TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id).DefaultTestSampleRate, false, defaultAAFRate, TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id).DefaultPTPDomainID);
}
}
else
{
// is not valid hardware in the db
// likely orphaned?
//Remove from the list of removed hardware because it is no longer valid.
invalidRemovedHardware.Add(id);
}
}
foreach (var id in invalidRemovedHardware)
{
// Clean up orphaned Ids
RemovedHardware = RemovedHardware.Where(h => h != id).ToArray();
}
foreach (var id in existingHardware)
{
if (!AddedHardware.Contains(id) && !RemovedHardware.Contains(id))
{
DeleteHardware(id);
}
}
}
catch (Exception ex)
{
APILogger.Log($"Exception in SaveHardware", ex);
}
}
private void UpdateExistingHardware(int id, int addOrRemove, double samplesPerSecond, bool isClockMaster, float antiAliasFilterRate, byte ptpDomainId)
{
var record = new TestSetupHardwareRecord()
{
AddDAS = 0 != addOrRemove,
SamplesPerSecond = Convert.ToInt32(samplesPerSecond),
DASId = id,
TestSetupId = Id,
IsClockMaster = isClockMaster,
AntiAliasFilterRate = Convert.ToInt32(antiAliasFilterRate),
PTPDomainId = ptpDomainId
};
_ = DbOperations.TestSetupHardwareUpdate(record);
}
private void InsertHardware(int id, int addOrRemove, double samplesPerSecond, bool isClockMaster, float antiAliasFilterRate, byte ptpDomainId)
{
var record = new TestSetupHardwareRecord()
{
AddDAS = 0 != addOrRemove,
SamplesPerSecond = Convert.ToInt32(samplesPerSecond),
DASId = id,
TestSetupId = Id,
IsClockMaster = isClockMaster,
AntiAliasFilterRate = Convert.ToInt32(antiAliasFilterRate),
PTPDomainId = ptpDomainId
};
_ = DbOperations.TestSetupHardwareInsert(record);
}
private void DeleteHardware(int id)
{
_ = DbOperations.TestSetupHardwareDelete(null, id, Id);
}
private int[] GetExistingHardwareIds()
{
var testSetupHardwareGetWrapper = new TestSetupHardwareGet();
var testSetupHardwareGetList = testSetupHardwareGetWrapper.TestSetupHardwareGet_Wrapper(Id, null);
var list = new List<int>();
foreach (var testSetupGet in testSetupHardwareGetList)
{
var id = testSetupGet.DASId;
list.Add(id);
}
return list.ToArray();
}
public void RemoveGroup(IGroup group)
{
ChannelsForGroup.Remove(group);
Groups.Remove(group);
for (var i = 0; i < Groups.Count; i++)
{
Groups[i].DisplayOrder = 1 + i;
}
OnPropertyChanged("Groups");
}
public List<IGroupChannel> GetChannels()
{
var channels = new List<IGroupChannel>();
using (var enumChannels = ChannelsForGroup.GetEnumerator())
{
while (enumChannels.MoveNext())
{
channels.AddRange(enumChannels.Current.Value);
}
}
channels.Sort();
return channels;
}
/// <summary>
/// moves the group up, and all channels in the group before all channels in groups after this group
/// </summary>
/// <param name="group"></param>
public void MoveGroupUp(IGroup @group)
{
var index = Groups.IndexOf(group);
if (0 == index) { return; }
Swap(index, index - 1);
var channels = GetChannels();
var groupAfterThisOne = new HashSet<int>();
var insertIndex = -1;
for (var i = index; i < Groups.Count; i++)
{
groupAfterThisOne.Add(Groups[i].Id);
}
//14045 Unhandled exception pulling updates for a group in a test.
var channelsForThisGroup = ChannelsForGroup[group].ToList();
foreach (var channel in channelsForThisGroup)
{
channels.Remove(channel);
}
//now we want to find the first channel for all groups after this group
for (var i = 0; i < channels.Count; i++)
{
if (null == channels[i].Group) { continue; }
if (channels[i].IsBlank()) { continue; }
if (groupAfterThisOne.Contains(channels[i].Group.Id))
{
insertIndex = i;
break;
}
}
if (insertIndex < 0)
{
insertIndex = 0;
}
channelsForThisGroup.Sort();
//insert at the given point in reverse order
for (var i = channelsForThisGroup.Count - 1; i >= 0; i--)
{
channels.Insert(insertIndex, channelsForThisGroup[i]);
}
for (var i = 0; i < channels.Count; i++)
{
if (channels[i].IsBlank()) { continue; }
channels[i].TestSetupOrder = 1 + i;
}
}
/// <summary>
/// moves the group down and all channels in the group after all channels in groups before this group
/// </summary>
/// <param name="group"></param>
public void MoveGroupDown(IGroup @group)
{
var index = Groups.IndexOf(group);
if (Groups.Last() == group) { return; }
Swap(index, index + 1);
//find the last channel for all groups before this one
var groupsBeforeThisOne = new HashSet<int>();
for (var i = 0; i < index + 1; i++)
{
groupsBeforeThisOne.Add(Groups[i].Id);
}
var channels = GetChannels();
var channelsForGroup = ChannelsForGroup[group].ToList();
channelsForGroup.Sort();
foreach (var channel in channelsForGroup)
{
channels.Remove(channel);
}
var insertPoint = -1;
for (var i = channels.Count - 1; i >= 0; i--)
{
if (channels[i].IsBlank()) { continue; }
if (null == channels[i].Group) { continue; }
if (groupsBeforeThisOne.Contains(channels[i].Group.Id))
{
insertPoint = i + 1;
break;
}
}
if (insertPoint < 0)
{
insertPoint = 0;
}
for (var i = channelsForGroup.Count - 1; i >= 0; i--)
{
channels.Insert(insertPoint, channelsForGroup[i]);
}
for (var i = 0; i < channels.Count; i++)
{
if (channels[i].IsBlank()) { continue; }
channels[i].TestSetupOrder = 1 + i;
}
}
private void Swap(int sourceIndex, int destIndex)
{
var displayOrder = Groups[sourceIndex].DisplayOrder;
Groups[sourceIndex].DisplayOrder = Groups[destIndex].DisplayOrder;
Groups[destIndex].DisplayOrder = displayOrder;
Groups.Move(sourceIndex, destIndex);
OnPropertyChanged("Groups");
}
public void MoveGroupToDisplayOrder(IGroup groupToMove, int destDisplayOrder)
{
//14045 Unhandled exception pulling updates for a group in a test.
if (destDisplayOrder < 1)
{
destDisplayOrder = 1;
}
var destIndex = destDisplayOrder - 1; // //Index is 0-relative
while (!Groups[destIndex].Equals(groupToMove))
{
MoveGroupUp(groupToMove);
}
}
private void UpdateGroupInTestSetup(IGroup group)
{
_ = DbOperations.TestSetupGroupsUpdate(new
TestSetupGroupRecord()
{
GroupId = group.Id,
DisplayOrder = group.DisplayOrder,
Position = group.Position,
TestObjectType = group.TestObject,
TestSetupId = Id
});
}
private void InsertGroupIntoTest(IGroup group)
{
_ = DbOperations.TestSetupGroupsInsert(new
TestSetupGroupRecord()
{
GroupId = group.Id,
TestSetupId = Id,
DisplayOrder = group.DisplayOrder,
Position = group.Position,
TestObjectType = group.TestObject
});
}
private void DeleteGroupsFromTest(int[] ids)
{
foreach (var id in ids)
{
var errorNumber = DbOperations.GroupsDelete(id, out string errorMessage);
if (errorNumber != 0)
{
throw new Exception(errorMessage);
}
}
}
private int[] GetExistingGroupIds()
{
var ids = new List<int>();
var hr = DbOperations.TestSetupGroupsGet(null, Id, Name, out var records);
if (0 == hr && null != records && records.Any())
{
foreach (var record in records)
{
ids.Add(record.GroupId);
}
}
return ids.ToArray();
}
private bool GetIsCompleteNoFunctions()
{
return base.IsComplete;
}
public TestTemplate(TestTemplate copy)
: base(copy)
{
//this constructor is already pretty long, so I put all the
//TSRAir settings that need to be intiialized by copy constr into their own method
CopyTSRAirSettings(copy);
_downloadFolder = DataModelSettings.DownloadFolder;
_exportFolder = DataModelSettings.DownloadFolder;
_defaultDownloadFolder = DataModelSettings.DownloadFolder;
IsQuickCheckout = copy.IsQuickCheckout;
var settings = TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id);
_settings = new TestSettingDictionary(copy._settings);
InitializeFromDefaults(settings.DefaultSensorCalibrationBehavior, settings.DefaultRecordingMode,
settings.DefaultPreTriggerSeconds, settings.DefaultPostTriggerSeconds, settings.DefaultNumberOfEvents);
OldTestTemplateLiteCopy(copy);
IsComplete = copy.GetIsCompleteNoFunctions(); //FB16057: assign from lite, testtemplate.iscomplete.get() can cause a recalc and unload
try
{
if (!copy.IsLoaded) { copy.Load(); }
}
catch (Exception ex) { APILogger.Log(ex); }
QuickSensorCheck = copy.QuickSensorCheck;
ISFFile = copy.ISFFile;
ExpressTestSetup = copy.ExpressTestSetup;
using (var eHardware = copy.HardwareOverrides.GetEnumerator())
{
while (eHardware.MoveNext())
{
HardwareOverrides[eHardware.Current.Key] =
new HardwareInclusionInstruction(eHardware.Current.Value);
}
}
using (var eLevelTrigger = copy.LevelTriggerChannels.GetEnumerator())
{
while (eLevelTrigger.MoveNext())
{
LevelTriggerChannels[eLevelTrigger.Current.Key] =
new LevelTriggerChannel(eLevelTrigger.Current.Value);
}
}
foreach (var cc in copy.CalculatedChannels)
{
CalculatedChannels.Add(new CalculatedValueClass(cc));
}
AllowMissingSensors = copy.AllowMissingSensors;
AllowSensorIdToBlankChannel = copy.AllowSensorIdToBlankChannel;
AutomaticProgression = copy.AutomaticProgression;
AutomaticProgressionDelayMS = copy.AutomaticProgressionDelayMS;
AutoVerifyChannels = copy.AutoVerifyChannels;
AutoVerifyDelaySeconds = copy.AutoVerifyDelaySeconds;
CalibrationBehavior = copy.CalibrationBehavior;
CheckedDASList = copy.CheckedDASList;
if (null != copy.CustomerDetails)
{
CustomerDetails = new CustomerDetails(copy.CustomerDetails.GetISOCustomer());
}
if (null != copy.TestEngineerDetails)
{
TestEngineerDetails = new TestEngineerDetails(copy.TestEngineerDetails.GetISOTestEngineer());
}
foreach (var setting in copy.DASSettings)
{
var newSetting = new DASSettings(setting);
_dasSettings[setting.DASSerialNumber] = newSetting;
}
DefaultNumberRealtimeGraphs = copy.DefaultNumberRealtimeGraphs;
Description = copy.Description;
WarnOnFailedBattery = copy.WarnOnFailedBattery;
DoROIDownload = copy.DoROIDownload;
DownloadAll = copy.DownloadAll;
ExcitationWarmup = copy.ExcitationWarmup;
ExcitationWarmupTimeMS = ExcitationWarmup;
ExportFormats = copy.ExportFormats;
InvertStartRecordCompletion = copy.InvertStartRecordCompletion;
InvertTriggerCompletion = copy.InvertTriggerCompletion;
IgnoreShortedStartCompletion = copy.IgnoreShortedStartCompletion;
IgnoreShortedTriggerCompletion = copy.IgnoreShortedTriggerCompletion;
TriggerCheckRealtime = copy.TriggerCheckRealtime;
TriggerCheckStep = copy.TriggerCheckStep;
PostTestDiagnosticsLevel = copy.PostTestDiagnosticsLevel;
MeasureSquibResistancesStep = copy.MeasureSquibResistancesStep;
if (null != copy.LabDetails)
{
LabDetails = new LabratoryDetails(copy.LabDetails.GetIsoLab());
}
LastModified = copy.LastModified;
LastModifiedBy = copy.LastModifiedBy;
LocalOnly = copy.LocalOnly;
Name = copy.Name;
TestSetupUniqueId = copy.TestSetupUniqueId;
PostTriggerSeconds = copy.PostTriggerSeconds;
PreTriggerSeconds = copy.PreTriggerSeconds;
RecordingMode = copy.RecordingMode;
NumberOfEvents = copy.NumberOfEvents;
WakeUpMotionTimeout = copy.WakeUpMotionTimeout;
RequireUserConfirmationOnErrors = copy.RequireUserConfirmationOnErrors;
RegionsOfInterest = copy.RegionsOfInterest;
ROIEnd = copy.ROIEnd;
ROIStart = copy.ROIStart;
SamplesPerSecondAggregate = copy.SamplesPerSecondAggregate;
StrictDiagnostics = copy.StrictDiagnostics;
foreach (var tg in copy.TestGraphs) { _testGraphs.Add(new TestGraph(tg)); }
//this is not needed, we could always sort whenever we use it, and it's probably already sorted
//but just for safety since we just copied a bunch of stuff, sort it!
TestObjectsAndAddedGroupsList.Sort();
TurnOffExcitation = copy.TurnOffExcitation;
ExtraProperties = copy.ExtraProperties;
TestDirectory = copy.TestDirectory;
TestId = copy.TestId;
TestIdNode = copy.TestIdNode;
VerifyChannels = copy.VerifyChannels;
CommonLine = copy.CommonLine;
UploadData = copy.UploadData;
UploadExportsOnly = copy.UploadExportsOnly;
UploadFolder = copy.UploadFolder;
ViewDiagnostics = copy.ViewDiagnostics;
ViewDownloadAll = copy.ViewDownloadAll;
ViewExport = copy.ViewExport;
ViewRealtime = copy.ViewRealtime;
ViewROIDownload = copy.ViewROIDownload;
ExportFolder = copy.ExportFolder;
DownloadFolder = copy.DownloadFolder;
SameAsDownloadFolder = copy.SameAsDownloadFolder;
DoAutoArm = copy.DoAutoArm;
DoEnableRepeat = copy.DoEnableRepeat;
DoStreaming = copy.DoStreaming;
CheckoutMode = copy.CheckoutMode;
QuitTestWithoutWarning = copy.QuitTestWithoutWarning;
SuppressMissingSensorsWarning = copy.SuppressMissingSensorsWarning;
NotAllChannelsRealTime = copy.NotAllChannelsRealTime;
NotAllChannelsViewer = copy.NotAllChannelsViewer;
ClockSyncProfileMaster = copy.ClockSyncProfileMaster;
ClockSyncProfileSlave = copy.ClockSyncProfileSlave;
foreach (var md in copy.GetMetaData())
{
SetMetaData(md.TestObject, new TestObjectMetaData(md));
}
SetTestSetupMetaData(new TestSetupMetaData(copy.GetTestMetaData()));
lock (SensorLock)
{
SensorLookup = new Dictionary<string, Dictionary<string, Dictionary<string, SensorData>>>();
using (var e = copy.SensorLookup.GetEnumerator())
{
while (e.MoveNext())
{
if (!SensorLookup.ContainsKey(e.Current.Key))
{
SensorLookup.Add(e.Current.Key, new Dictionary<string, Dictionary<string, SensorData>>());
}
using (var e2 = e.Current.Value.GetEnumerator())
{
while (e2.MoveNext())
{
if (!SensorLookup[e.Current.Key].ContainsKey(e2.Current.Key))
{
SensorLookup[e.Current.Key]
.Add(e2.Current.Key, new Dictionary<string, SensorData>());
}
using (var e3 = e2.Current.Value.GetEnumerator())
{
while (e3.MoveNext())
{
SensorLookup[e.Current.Key][e2.Current.Key][e3.Current.Key] = e3.Current.Value;
}
}
}
}
}
}
}
ErrorMessage = copy.ErrorMessage;
//avoid recalculating, just copy the value
IsComplete = copy.GetIsCompleteNoFunctions();
Dirty = copy.Dirty;
_bIsLoaded = copy._bIsLoaded;
TagsBlobBytes = copy.TagsBlobBytes;
DestructiveTest = copy.DestructiveTest;
}
#endregion Constructor
#region Properties
private readonly Dictionary<string, DASSettings> _dasSettings = new Dictionary<string, DASSettings>();
public DASSettings[] DASSettings
{
get => _dasSettings.Count < 1 ? new DASSettings[0] : _dasSettings.Values.ToArray();
set
{
_dasSettings.Clear();
foreach (var setting in value) { _dasSettings[setting.DASSerialNumber] = setting; }
}
}
private bool _bExpressTestSetup;
public bool ExpressTestSetup
{
get => _bExpressTestSetup;
set => SetProperty(ref _bExpressTestSetup, value, TestTemplateTags.ExpressTestSetup.ToString());
}
/// <summary>
/// this controls whether test id and description should be preserved
/// this is generally set once the basic info page has been hit
/// </summary>
private bool _preserveTestId;
public bool PreserveTestId
{
get => QuickSensorCheck || _preserveTestId;
set => SetProperty(ref _preserveTestId, value, "PreserveTestId");
}
/// <summary>
/// whether all units in the test share a common line
/// this should be set to false if DAS in the test don't share a common line
/// the default is true
/// if units share a common status line and there are multiple units in the test, then each unit will monitor the status line
/// if false or there's only one unit, the status line should not be monitored
/// </summary>
public bool CommonLine
{
get => CommonStatusLine;
set
{
CommonStatusLine = value;
OnPropertyChanged("CommonLine");
}
}
/// <summary>
/// true if the test objects and other fields have already been loaded from the database, false otherwise
/// </summary>
internal bool _bIsLoaded;
public bool IsLoaded => _bIsLoaded;
public static bool DASSamplesPerPacketUpToDate { get; set; }
public void SetIsLoaded(bool bIsLoaded)
{
_bIsLoaded = bIsLoaded;
}
public bool ArmCheckListStep
{
get
{
if (SerializedSettings.AutoAddArmChecklist && CheckForTOM() && DataModelSettings.ArmChecklistRequiredIfTOM)
{
return true;
}
return Convert.ToBoolean(GetSetting(TestSettingsEnum.ArmCheckListStep));
}
set => SetSetting(TestSettingsEnum.ArmCheckListStep, value.ToString());
}
public bool CheckListBatteryVoltageCheck
{
get => Convert.ToBoolean(GetSetting(TestSettingsEnum.CheckListBatteryVoltageCheck));
set => SetSetting(TestSettingsEnum.CheckListBatteryVoltageCheck, value.ToString());
}
public bool CheckListInputVoltageCheck
{
get => Convert.ToBoolean(GetSetting(TestSettingsEnum.CheckListInputVoltageCheck));
set => SetSetting(TestSettingsEnum.CheckListInputVoltageCheck, value.ToString());
}
public bool CheckListSquibResistanceCheck
{
get => Convert.ToBoolean(GetSetting(TestSettingsEnum.CheckListSquibResistanceCheck));
set => SetSetting(TestSettingsEnum.CheckListSquibResistanceCheck, value.ToString());
}
public bool CheckListSensorIdCheck
{
get => Convert.ToBoolean(GetSetting(TestSettingsEnum.CheckListSensorIDCheck));
set => SetSetting(TestSettingsEnum.CheckListSensorIDCheck, value.ToString());
}
public bool CheckListRequirePass
{
get => Convert.ToBoolean(GetSetting(TestSettingsEnum.CheckListMustPass));
set => SetSetting(TestSettingsEnum.CheckListMustPass, value.ToString());
}
public bool CheckListTiltSensorCheck
{
get => Convert.ToBoolean(GetSetting(TestSettingsEnum.CheckListTiltSensorCheck));
set => SetSetting(TestSettingsEnum.CheckListTiltSensorCheck, value.ToString());
}
public bool CheckListTemperatureCheck
{
get => Convert.ToBoolean(GetSetting(TestSettingsEnum.CheckListTemperatureCheck));
set => SetSetting(TestSettingsEnum.CheckListTemperatureCheck, value.ToString());
}
public bool CheckListClockSyncCheck
{
get => Convert.ToBoolean(GetSetting(TestSettingsEnum.CheckListClockSyncCheck));
set => SetSetting(TestSettingsEnum.CheckListClockSyncCheck, value.ToString());
}
/// <summary>
/// engineer meta data (can differ from the record for the engineer in the db)
/// </summary>
public TestEngineerDetailsDbRecord EngineerOverride
{
get => GetEngineerFromMeta();
set => SetEngineerMetaData(value);
}
/// <summary>
/// produces an engineer from meta data
/// </summary>
private TestEngineerDetailsDbRecord GetEngineerFromMeta()
{
var record = new TestEngineerDetailsDbRecord();
var meta = GetTestMetaData();
record.TestEngineerEmail = meta.GetPropertyValue(TestSetupMetaData.Fields.TestEngineerEmail);
record.TestEngineerFax = meta.GetPropertyValue(TestSetupMetaData.Fields.TestEngineerFax);
record.TestEngineerName = meta.GetPropertyValue(TestSetupMetaData.Fields.TestEngineerName);
record.TestEngineerPhone = meta.GetPropertyValue(TestSetupMetaData.Fields.TestEngineerPhone);
return record;
}
/// <summary>
/// stores engineer in meta data
/// </summary>
public void SetEngineerMetaData(TestEngineerDetailsDbRecord record)
{
var meta = GetTestMetaData();
meta.SetPropertyValue(TestSetupMetaData.Fields.TestEngineerEmail, record.TestEngineerEmail);
meta.SetPropertyValue(TestSetupMetaData.Fields.TestEngineerFax, record.TestEngineerFax);
meta.SetPropertyValue(TestSetupMetaData.Fields.TestEngineerName, record.TestEngineerName);
meta.SetPropertyValue(TestSetupMetaData.Fields.TestEngineerPhone, record.TestEngineerPhone);
}
/// <summary>
/// customer meta data (can differ from customer record in db)
/// </summary>
public CustomerDetailsDbRecord CustomerOverride
{
get => GetCustomerFromMeta();
set => SetCustomerMetaData(value);
}
/// <summary>
/// retrieves a customer from meta data
/// </summary>
private CustomerDetailsDbRecord GetCustomerFromMeta()
{
var record = new CustomerDetailsDbRecord();
var meta = GetTestMetaData();
record.CustomerCostUnit = meta.GetPropertyValue(TestSetupMetaData.Fields.CustomerCostUnit);
record.CustomerName = meta.GetPropertyValue(TestSetupMetaData.Fields.CustomerName);
record.CustomerOrderNumber = meta.GetPropertyValue(TestSetupMetaData.Fields.CustomerOrderNumber);
record.ProjectRefNumber = meta.GetPropertyValue(TestSetupMetaData.Fields.CustomerProjectReferenceNumber);
record.CustomerTestRefNumber = meta.GetPropertyValue(TestSetupMetaData.Fields.CustomerTestReferenceNumber);
return record;
}
/// <summary>
/// stores a customer in meta data
/// </summary>
public void SetCustomerMetaData(CustomerDetailsDbRecord record)
{
var meta = GetTestMetaData();
meta.SetPropertyValue(TestSetupMetaData.Fields.CustomerCostUnit, record.CustomerCostUnit);
meta.SetPropertyValue(TestSetupMetaData.Fields.CustomerName, record.CustomerName);
meta.SetPropertyValue(TestSetupMetaData.Fields.CustomerOrderNumber, record.CustomerOrderNumber);
meta.SetPropertyValue(TestSetupMetaData.Fields.CustomerProjectReferenceNumber, record.ProjectRefNumber);
meta.SetPropertyValue(TestSetupMetaData.Fields.CustomerTestReferenceNumber, record.CustomerTestRefNumber);
}
/// <summary>
/// lab meta data (can differ from lab record in db)
/// </summary>
public LabratoryDetailsDbRecord LabOverride
{
get => GetLabFromMeta();
set => SetLabMetaData(value);
}
/// <summary>
/// retrieves a lab from meta data
/// </summary>
private LabratoryDetailsDbRecord GetLabFromMeta()
{
var meta = GetTestMetaData();
var record = new LabratoryDetailsDbRecord();
record.LabratoryContactEmail = meta.GetPropertyValue(TestSetupMetaData.Fields.LaboratoryContactEmail);
record.LabratoryContactFax = meta.GetPropertyValue(TestSetupMetaData.Fields.LaboratoryContactFax);
record.LabratoryContactName = meta.GetPropertyValue(TestSetupMetaData.Fields.LaboratoryContactName);
record.LabratoryContactPhone = meta.GetPropertyValue(TestSetupMetaData.Fields.LaboratoryContactPhone);
record.LabratoryName = meta.GetPropertyValue(TestSetupMetaData.Fields.LaboratoryName);
record.LabratoryProjectRefNumber = meta.GetPropertyValue(TestSetupMetaData.Fields.LaboratoryProjectReferenceNumber);
record.LabratoryTestRefNumber = meta.GetPropertyValue(TestSetupMetaData.Fields.LaboratoryTestReferenceNumber);
return record;
}
/// <summary>
/// stores a lab in meta data
/// </summary>
public void SetLabMetaData(LabratoryDetailsDbRecord record)
{
var meta = GetTestMetaData();
meta.SetPropertyValue(TestSetupMetaData.Fields.LaboratoryContactEmail, record.LabratoryContactEmail);
meta.SetPropertyValue(TestSetupMetaData.Fields.LaboratoryContactFax, record.LabratoryContactFax);
meta.SetPropertyValue(TestSetupMetaData.Fields.LaboratoryContactName, record.LabratoryContactName);
meta.SetPropertyValue(TestSetupMetaData.Fields.LaboratoryContactPhone, record.LabratoryContactPhone);
meta.SetPropertyValue(TestSetupMetaData.Fields.LaboratoryName, record.LabratoryName);
meta.SetPropertyValue(TestSetupMetaData.Fields.LaboratoryProjectReferenceNumber, record.LabratoryProjectRefNumber);
meta.SetPropertyValue(TestSetupMetaData.Fields.LaboratoryTestReferenceNumber, record.LabratoryTestRefNumber);
}
/// <summary>
/// returns the error messages for a test setup
/// calculated at the same time is complete is calculated, however doesn't have a check against
/// is dirty, like IsComplete does ...
/// </summary>
public string CompletionErrorMessage => ErrorMessage.Length > 250 ? ErrorMessage.Substring(0, 250) : ErrorMessage;
/// <summary>
/// returns whether the test setup is complete or not.
/// WILL FORCE IsComplete TO BE CALCULATED IF IsDirty is true
/// (you might not want this if you are adding a new test setup for instance...)
/// </summary>
public bool IsComplete
{
get
{
if (string.IsNullOrWhiteSpace(Name)) { return false; }
//TODO: review property functionality
if (IsDirty) { CalculateIsComplete(); }
return base.IsComplete;
}
set => base.IsComplete = value;
}
public bool IsDirty
{
get => Dirty;
set => Dirty = value;
}
private DTS.Serialization.Test _test;
public DTS.Serialization.Test Test
{
get => _test;
set => SetProperty(ref _test, value, TestTemplateTags.Test.ToString());
}
private Dictionary<HardwareChannel, DASHardware> _dasLookup;
private Dictionary<string, double> _filterLookup = new Dictionary<string, double>();
public Dictionary<string, double> FilterLookup
{
get => _filterLookup;
set => _filterLookup = value;
}
/// <summary>
/// excitation warmup time
/// can be defined at test level, test object level, (and maybe at hardware or channel level?)
/// if defined here, we return it right away, otherwise we pass it to the max of the test objets
/// </summary>
public int ExcitationWarmupTimeMS
{
get => ExcitationWarmup;
set
{
if (int.MinValue != value)
{
foreach (var to in TestObjects) { to.ExcitationWarmupTimeMS = value; }
ExcitationWarmup = value;
OnPropertyChanged("ExcitationWarmupTimeMS");
}
}
}
private List<TestGraph> _testGraphs = new List<TestGraph>();
public TestGraph[] TestGraphs
{
get => _testGraphs.ToArray();
set { SetProperty(ref _testGraphs, new List<TestGraph>(value), TestTemplateTags.TestGraphs.ToString()); OnPropertyChanged(TestTemplateTags.GraphCount.ToString()); }
}
public int GraphCount => _testGraphs.Count;
public void AddGroup(IGroup group, IChannelSetting[] channelDefaults)
{
var sensorLookup = new Dictionary<int, ISensorData>();
var sensors = SensorsCollection.SensorsList.GetAllSensors(false);
foreach (var s in sensors)
{
sensorLookup[s.DatabaseId] = s;
}
var hardwareLookup = new Dictionary<int, IDASHardware>();
var hardware = DASHardwareList.GetAllHardware();
foreach (var h in hardware)
{
hardwareLookup[h.DASId] = h;
}
AddGroup(group, sensorLookup, hardwareLookup, channelDefaults);
OnPropertyChanged("Groups");
}
public void AddGroup(IGroup group, IDictionary<long, IGroupChannel> channelLookup, ISensorData[] sensors = null)
{
var sensorLookup = new Dictionary<int, ISensorData>();
if (null == sensors)
{
sensors = SensorsCollection.SensorsList.GetAllSensors(false);
}
foreach (var s in sensors)
{
sensorLookup[s.DatabaseId] = s;
}
_groups.Add(group);
AddGroup(group, sensorLookup, channelLookup);
OnPropertyChanged("Groups");
}
public TestGraph CurrentGraph
{
get
{
var selected = (from g in TestGraphs.AsParallel() where g.Selected select g);
if (selected.Any())
{
return selected.First();
}
return null;
}
}
public new bool UseCustomerDetails
{
get
{
var customerOverride = CustomerOverride;
return !IsBlank(customerOverride);
}
}
private const string NOVALUE = "NOVALUE";
private bool IsBlank(CustomerDetailsDbRecord record)
{
if (!string.IsNullOrEmpty(record.Name)) { return false; }
if (!string.IsNullOrWhiteSpace(record.CustomerName) && !NOVALUE.Equals(record.CustomerName)) { return false; }
if (!string.IsNullOrWhiteSpace(record.CustomerOrderNumber) && !NOVALUE.Equals(record.CustomerOrderNumber)) { return false; }
if (!string.IsNullOrWhiteSpace(record.CustomerTestRefNumber) && !NOVALUE.Equals(record.CustomerTestRefNumber)) { return false; }
if (!string.IsNullOrWhiteSpace(record.ProjectRefNumber) && !NOVALUE.Equals(record.ProjectRefNumber)) { return false; }
return true;
}
public new bool UseTestEngineerDetails
{
get
{
var overrideEngineer = EngineerOverride;
return !IsBlank(overrideEngineer);
}
}
private bool IsBlank(TestEngineerDetailsDbRecord record)
{
if (!string.IsNullOrWhiteSpace(record.Name)) { return false; }
if (!string.IsNullOrWhiteSpace(record.TestEngineerEmail) && !NOVALUE.Equals(record.TestEngineerEmail))
{
return false;
}
if (!string.IsNullOrWhiteSpace(record.TestEngineerFax) && !NOVALUE.Equals(record.TestEngineerFax))
{
return false;
}
if (!string.IsNullOrWhiteSpace(record.TestEngineerName) && !NOVALUE.Equals(record.TestEngineerName))
{
return false;
}
if (!string.IsNullOrWhiteSpace(record.TestEngineerPhone) && !NOVALUE.Equals(record.TestEngineerPhone))
{
return false;
}
return true;
}
public new bool UseLabratoryDetails
{
get
{
var labOverride = LabOverride;
return !IsBlank(labOverride);
}
}
private bool IsBlank(LabratoryDetailsDbRecord record)
{
if (!string.IsNullOrWhiteSpace(record.Name)) { return false; }
if (!string.IsNullOrWhiteSpace(record.LabratoryContactEmail) && !NOVALUE.Equals(record.LabratoryContactEmail))
{
return false;
}
if (!string.IsNullOrWhiteSpace(record.LabratoryContactFax) && !NOVALUE.Equals(record.LabratoryContactFax))
{
return false;
}
if (!string.IsNullOrWhiteSpace(record.LabratoryContactName) && !NOVALUE.Equals(record.LabratoryContactName))
{
return false;
}
if (!string.IsNullOrWhiteSpace(record.LabratoryContactPhone) & !NOVALUE.Equals(record.LabratoryContactPhone))
{
return false;
}
if (!string.IsNullOrWhiteSpace(record.LabratoryName) && !NOVALUE.Equals(record.LabratoryName)) { return false; }
if (!string.IsNullOrWhiteSpace(record.LabratoryProjectRefNumber) && !NOVALUE.Equals(record.LabratoryProjectRefNumber))
{
return false;
}
if (!string.IsNullOrWhiteSpace(record.LabratoryTestRefNumber) && !NOVALUE.Equals(record.LabratoryTestRefNumber))
{
return false;
}
return true;
}
public TestTestObject[] TestObjectsWithChannels
{
get
{
var list = new List<TestTestObject>(_testObjects);
for (var i = list.Count - 1; i >= 0; i--)
{
var isoTestObject = list[i].GetISOTestObject();
if (0 == isoTestObject.AllChannels.Length) { list.RemoveAt(i); }
}
return list.ToArray();
}
}
//assumes list is in order and sets display orders accordingly
private bool SampleRatesAreMixed()
{
try
{
var currentTestHardware = GetHardware();
var firstSampleRate = 0.0D;
if (currentTestHardware.Length > 0)
{
firstSampleRate = DASSampleRateList[currentTestHardware[0].SerialNumber];
}
//Determine if any are different by comparing to the first ([0]).
foreach (var das in currentTestHardware)
{
if (DASSampleRateList[das.SerialNumber] != firstSampleRate)
{
return true;
}
}
return false;
}
catch (Exception)
{
//found an issue when working on
//16117 Sensors and groups tables not populated when using recovery controls feature in download tab
//where the xml could contain many hardware, but the test wouldn't have definitions for them (at least not the first one)
//so this approach may be safer when that happens,
//but I didn't feel confident to make it the default behavior ...
if (DASAAFRateList.Values.ToArray().Distinct().Count() > 1) { return true; }
return false;
}
}
public List<TestTestObject> TestObjectsAndAddedGroupsList = new List<TestTestObject>();
public TestTestObject[] TestObjectsAndAddedGroups => TestObjectsAndAddedGroupsList.ToArray();
private List<TestTestObject> _testObjects = new List<TestTestObject>();
public TestTestObject[] TestObjects
{
get => _testObjects.ToArray();
set => SetTestObjects(false, value);
}
private List<TestTestObject> _addedGroups = new List<TestTestObject>();
public TestTestObject[] AddedGroups
{
get => _addedGroups.ToArray();
set
{
//MarkIsCompleteUnchecked(); Removed to fix FB 10241 with the assumption that simply Setting AddedGroups should not cause a database write.
SetProperty(ref _addedGroups, new List<TestTestObject>(value), TestTemplateTags.SysBuiltTestObjectTypes.ToString());
OnPropertyChanged(TestTemplateTags.AllTestObjects.ToString());//check this
OnPropertyChanged("TestObjectsAndAddedGroups");
OnPropertyChanged(TestTemplateTags.TestObjectsAndAddedGroups.ToString());
}
}
private List<TestTestObject> _otherAddedGroups = new List<TestTestObject>();
public TestTestObject[] OtherAddedGroups
{
get => _otherAddedGroups.ToArray();
set => _otherAddedGroups = value.ToList();
}
public double MaxSampleRate
{
get
{
if (0 < TestObjects.Length || 0 < AddedGroups.Length)
{
return (from TestObject to in AddedGroups from h in to.Hardware select h.GetMaxSampleRateDouble()).Concat(new[] { double.MaxValue }).Min();
}
return double.MaxValue;
}
}
public double MinSampleRate
{
get
{
if (0 < TestObjects.Length || 0 < AddedGroups.Length)
{
return (from TestObject to in AddedGroups from h in to.Hardware select h.GetMinSampleRateDouble()).Concat(new[] { 0.00 }).Max();
}
return 0;
}
}
private List<TestTestObject> _allTestObjects = new List<TestTestObject>();
public TestTestObject[] AllTestObjects
{
get
{
_allTestObjects = new List<TestTestObject>();
foreach (var to in TestObjects)
{
_allTestObjects.Add(to);
}
foreach (var to in AddedGroups)
{
if (to.Hardware.Any()) { _allTestObjects.Add(to); }
}
return _allTestObjects.ToArray();
}
set
{
SetProperty(ref _allTestObjects, new List<TestTestObject>(value), TestTemplateTags.AllTestObjects.ToString());
OnPropertyChanged(TestTemplateTags.AvailableTestObjects.ToString());
}
}
public string SampleRateText
{
get => SamplesPerSecondAggregate.ToString();
set => SamplesPerSecondAggregate = double.Parse(value);
}
public Visibility ROIButtonVisibility => DoROIDownload ? Visibility.Visible : Visibility.Collapsed;
public Visibility ViewROIDownloadVisibility => ViewROIDownload ? Visibility.Visible : Visibility.Collapsed;
public Visibility ViewRealtimeButtonVisibility => ViewRealtime ? Visibility.Visible : Visibility.Collapsed;
public Visibility DownloadAllButtonVisibility => DownloadAll ? Visibility.Visible : Visibility.Collapsed;
public Visibility VerifyButtonVisibility => VerifyChannels ? Visibility.Visible : Visibility.Collapsed;
public Visibility ViewDownloadAllButtonVisibility => ViewDownloadAll ? Visibility.Visible : Visibility.Collapsed;
public string SPSText => SampleRatesAreMixed() ? StringResources.TestTemplate_MultipleSampleRates : SamplesPerSecondAggregate.ToString("N0");
public string RecordingModeText
{
get
{
switch (RecordingMode)
{
case RecordingModes.CircularBuffer: return StringResources.RecordingModes_CircularBuffer;
case RecordingModes.RAMActive: return StringResources.RecordingModes_RAMActive;
case RecordingModes.MultipleEventRAMActive: return StringResources.RecordingModes_MultipleEventRAMActive;
case RecordingModes.CircularBufferAndStreamSubSample: return StringResources.RecordingModes_CircularBufferAndStreamSubSample;
case RecordingModes.CircularBufferPlusUART: return StringResources.RecordingModes_CircularBufferPlusUART;
case RecordingModes.Recorder: return StringResources.RecordingModes_Recorder;
case RecordingModes.RecorderAndStreamSubSample: return StringResources.RecordingModes_RecorderAndStreamSubSample;
case RecordingModes.RecorderPlusUART: return StringResources.RecordingModes_RecorderPlusUART;
case RecordingModes.HybridRecorder: return StringResources.RecordingModes_HybridRecorder;
case RecordingModes.ContinuousRecorder: return StringResources.RecordingModes_ContinuousRecorder;
case RecordingModes.S6A_DeviceStreamingOnly: return StringResources.RecordingModes_S6A_DeviceStreamingOnly;
case RecordingModes.Active: return StringResources.RecordingModes_Active;
//FB 6399 Multiple Event support
case RecordingModes.MultipleEventActive: return StringResources.RecordingModes_MultipleEventActive;
case RecordingModes.MultipleEventCircularBuffer: return StringResources.RecordingModes_MultipleEventCircularBuffer;
case RecordingModes.MultipleEventRecorder: return StringResources.RecordingModes_MultipleEventRecorder;
case RecordingModes.MultipleEventHybridRecorder: return StringResources.RecordingModes_MultipleEventHybridRecorder;
case RecordingModes.MultipleEventCircularBufferPlusUART: return StringResources.RecordingModes_MultipleEventCircularBufferPlusUART;
case RecordingModes.MultipleEventRecorderPlusUART: return StringResources.RecordingModes_MultipleEventRecorderPlusUART;
case RecordingModes.ContinuousRecorderPlusUART: return StringResources.RecordingModes_ContinuousRecorderPlusUART;
case RecordingModes.Streaming: return StringResources.RecordingModes_Streaming;
case RecordingModes.Scheduled: return StringResources.RecordingModes_Scheduled;
case RecordingModes.Interval: return StringResources.RecordingModes_Interval;
case RecordingModes.RecordOnBoot: return StringResources.RecordingModes_RecordOnBoot;
case RecordingModes.RecordOnBootPlusUART: return StringResources.RecordingModes_RecordOnBootPlusUART;
case RecordingModes.HybridAndStream: return StringResources.RecordingModes_HybridAndStream;
case RecordingModes.MultipleEventHybridAndStream: return StringResources.RecordingModes_MultipleEventHybridAndStream;
case RecordingModes.MultipleEventCircularBufferAndStream: return StringResources.RecordingModes_MultipleEventCircularBufferAndStream;
case RecordingModes.MultipleEventRecorderAndStream: return StringResources.RecordingModes_MultipleEventRecorderAndStream;
}
return "N/A";
}
}
public string PreAndPostTriggerTimeText
{
get
{
if (double.IsNaN(PreTriggerSeconds) || double.IsNaN(PostTriggerSeconds))
{
return StringResources.TestTemplate_MultipleRecordingPeriods;
}
return string.Format(StringResources.TestTemplate_RecordingPeriodText, PreTriggerSeconds, PostTriggerSeconds);
}
}
private LabratoryDetails _labDetails;
public new LabratoryDetails LabDetails
{
get => _labDetails;
set
{
base.LabDetails = null == value ? string.Empty : value.Name;
SetProperty(ref _labDetails, value, TestTemplateTags.LabDetails.ToString());
}
}
private CustomerDetails _customerDetails;
public new CustomerDetails CustomerDetails
{
get => _customerDetails;
set
{
base.CustomerDetails = null == value ? string.Empty : value.Name;
SetProperty(ref _customerDetails, value, TestTemplateTags.CustomerDetails.ToString());
}
}
private TestEngineerDetails _testEngineerDetails;
public new TestEngineerDetails TestEngineerDetails
{
get => _testEngineerDetails;
set
{
base.TestEngineerDetails = null == value ? string.Empty : value.Name;
SetProperty(ref _testEngineerDetails, value, TestTemplateTags.TestEngineerDetails.ToString());
}
}
private CustomerDetails[] _allCustomers = null;
private static readonly object CustomersLock = new object();
public CustomerDetails[] AllCustomers
{
get
{
lock (CustomersLock)
{
if (null == _allCustomers)
{
_allCustomers = CustomerDetailsList.GetAllCustomers();
}
return _allCustomers;
}
}
}
private readonly TestEngineerDetailsList _testEngineers = TestEngineerDetailsList.TestEngineerList;
public TestEngineerDetails[] AllTestEngineers => _testEngineers.TestEngineers;
private static readonly object LabLock = new object();
private LabratoryDetails[] _allLabs = null;
public LabratoryDetails[] AllLabs
{
get
{
lock (LabLock)
{
if (null == _allLabs)
{
_allLabs = LabratoryDetailsList.GetAllLabs();
}
}
return _allLabs;
}
}
public new int DefaultNumberRealtimeGraphs
{
get
{
//FB 13750 return 1 in UseTestChannelOrder mode
if (DataModelSettings.UseTestChannelOrder)
{
return 1;
}
switch (base.DefaultNumberRealtimeGraphs)
{
case 6:
return 6;
case 3:
return 3;
case 1:
default:
return 1;
}
}
set
{
base.DefaultNumberRealtimeGraphs = Convert.ToInt16(value);
OnPropertyChanged(TestTemplateTags.DefaultNumberRealtimeGraphs.ToString());
}
}
public Visibility GraphDetailsVisibility
{
get
{
if (TestGraphs.Length < 1) { return Visibility.Collapsed; }
var selected = from g in TestGraphs.AsParallel() where g.Selected select g;
return selected.Any() ? Visibility.Visible : Visibility.Collapsed;
}
set
{
OnPropertyChanged(TestTemplateTags.GraphDetailsVisibility.ToString());
OnPropertyChanged(TestTemplateTags.CurrentGraph.ToString());
}
}
public int ChannelCount
{
get
{
lock (CountLock)
{
var channels = GetChannels().Select(ch => !ch.IsBlank() && ch.SensorValid);
return channels.Count();
}
}
}
private int _includedChannelCount;
public int IncludedChannelCount
{
get
{
lock (CountLock)
{
_includedChannelCount = 0;
{
foreach (var to in TestObjects)
{
foreach (var ch in to.GetISOTestObject().AllChannels)
{
if (ch.Required && CheckedDASList.Contains(ch.GetDASId()))
{
_includedChannelCount++;
}
}
}
foreach (var to in AddedGroups)
{
foreach (var ch in to.GetISOTestObject().AllChannels)
{
if (ch.Required && CheckedDASList.Contains(ch.GetDASId()))
{
_includedChannelCount++;
}
}
}
}
}
return _includedChannelCount;
}
}
#endregion Properties
/// <summary>
/// if you use rename serial number method to create a new test setup, we have to go and recreate the groups.
/// groups are supposed to be unique to a test setup, and we don't want them to unintentionally share groups
/// <param name="bAddedGroups">whether operating on static or dynamic groups</param>
/// </summary>
public void Rename(bool bAddedGroups)
{
var objectsOut = new List<TestTestObject>();
var objectsIn = new List<TestTestObject>();
var oldIdToNewId = new Dictionary<string, string>();
var oldGroupToNewGroupSerialNumber = new Dictionary<string, string>();
if (bAddedGroups)
{
objectsIn.AddRange(AddedGroups);
}
else
{
objectsIn.AddRange(TestObjects);
}
foreach (var group in objectsIn)
{
TestTestObject ttoNew;
if (bAddedGroups)
{
ttoNew = new TestTestObject(group);
//note this, appears to be done in multiple disparate places, not sure why it's not done in one place
//I'm copying it out of EditTestSetupObjectsControl, I don't have enough time to unify it all into one place right now
//so I'll just add an issue to correct that later.
ttoNew.SerialNumber = Name + "_" + ttoNew.SerialNumberConverted;
ttoNew.Template.TemplateName = Guid.NewGuid().ToString();
ttoNew.Template.OriginalTemplateName = ttoNew.SerialNumber + "_Template";
var oldMetaData = GetTestMetaData();
oldMetaData.SetPropertyValue(TestSetupMetaData.Fields.Title, Name);
}
else
{
ttoNew = new TestTestObject(group, true);
}
objectsOut.Add(ttoNew);
var isoOld = group.GetISOTestObject();
var isoNew = ttoNew.GetISOTestObject();
oldGroupToNewGroupSerialNumber[isoOld.SerialNumber] = isoNew.SerialNumber;
for (var i = 0; i < isoOld.AllChannels.Length && i < isoNew.AllChannels.Length; i++)
{
var ch = isoOld.AllChannels[i];
if (!ch.Required)
{
continue;
}
var oldId = ch.GetId();
var newId = isoNew.AllChannels[i].GetId();
oldIdToNewId[oldId] = newId;
if (!bAddedGroups) continue;
isoNew.Template = ttoNew.Template.TemplateName;
isoNew.OriginalTemplate = isoNew.OriginalTemplate.Replace(group.TestSetupName, Name);
isoNew.OriginalSerialNumber = isoNew.OriginalSerialNumber.Replace(group.TestSetupName, Name);
}
}
if (oldIdToNewId.Count > 0)
{
ReplaceLevelTriggerChannel(oldIdToNewId, oldGroupToNewGroupSerialNumber);
ReplaceCalculatedChannel(oldIdToNewId);
ReplaceChannelSetting(oldIdToNewId, oldGroupToNewGroupSerialNumber);
}
if (bAddedGroups)
{
AddedGroups = objectsOut.ToArray();
}
else
{
TestObjects = objectsOut.ToArray();
}
}
public int GetMaxDisplayOrder()
{
var existingObjects = new List<TestObject>(TestObjects);
existingObjects.AddRange(AddedGroups);
return existingObjects.Aggregate(0, (current1, to) => to.GetISOTestObject().AllChannels.Aggregate(current1, (current, ch) => Math.Max(current, ch.DisplayOrder)));
}
/// <summary>
/// returns true if the test has multiple sample rates for recording, false otherwise
/// </summary>
/// <returns></returns>
public bool HasMultipleSampleRates()
{
var firstSampleRate = 0.0D;
var currentTestHardware = GetHardware();
if (currentTestHardware.Length > 0)
{
firstSampleRate = DASSampleRateList[currentTestHardware[0].SerialNumber];
}
foreach (var das in currentTestHardware)
{
var dasType = das.GetHardwareTypeEnum();
var rate = DASSampleRateList[das.SerialNumber];
if (rate != firstSampleRate)
{
return true;
}
}
return false;
}
public bool HasOBRDDR()
{
var currentTestHardware = GetHardware();
return Array.Exists(currentTestHardware, das => das.DASTypeEnum == HardwareTypes.S6A_EthernetRecorder);
}
#region LEVEL_TRIGGER
public Dictionary<string, LevelTriggerChannel> LevelTriggerChannels = new Dictionary<string, LevelTriggerChannel>();
// ReSharper disable once InconsistentNaming
public string GetLTKey(LevelTriggerChannel ch)
{
return $"{ch.HardwareChannelId}x{ch.SensorSerialNumber}";
}
public void RemoveLevelTrigger(LevelTriggerChannel channel)
{
var key = GetLTKey(channel);
if (LevelTriggerChannels.ContainsKey(key))
{
LevelTriggerChannels.Remove(key);
}
}
public void SetLevelTrigger(LevelTriggerChannel channel)
{
var key = GetLTKey(channel);
LevelTriggerChannels[key] = new LevelTriggerChannel(channel);//do a copy just for safety
if (null == channel.GroupChannel)
{
//lookup the channel?
//issue discovered by Nate, no issue # yet
if (long.TryParse(channel.GroupChannelId, out var l))
{
if (l > 0)
{
using (var eGroups = ChannelsForGroup.GetEnumerator())
{
while (eGroups.MoveNext())
{
var channels = eGroups.Current.Value;
if (!channels.Any()) { continue; }
var matches = from ch in channels where ch.Id == l select ch;
if (matches.Any())
{
var match = matches.First();
if (null != match)
{
LevelTriggerChannels[key].GroupChannel = match;
break;
}
}
}
}
}
}
}
else { LevelTriggerChannels[key].GroupChannel = channel.GroupChannel; }
}
public LevelTriggerChannel GetLevelTrigger(LevelTriggerChannel channel)
{
var key = GetLTKey(channel);
return LevelTriggerChannels.ContainsKey(key) ? LevelTriggerChannels[key] : null;
}
/// <summary>
/// replaces any level triggers that have a specific id, with another
/// brand new id
/// </summary>
/// <param name="oldId"></param>
/// <param name="newId"></param>
public void ReplaceLevelTriggerChannel(string oldId, string newId)
{
using (var e = LevelTriggerChannels.GetEnumerator())
{
while (e.MoveNext())
{
if (e.Current.Value.GroupChannelId == oldId)
{
e.Current.Value.GroupChannelId = newId;
}
}
}
}
/// <summary>
/// scans through all level triggers, looks for any level triggers that might be associated with an old group serial number
/// and replaces those references with the new group serial number
/// </summary>
/// <param name="oldGroupSerial"></param>
/// <param name="newGroupSerial"></param>
public void ReplaceLevelTriggerChannelGroupMapping(string oldGroupSerial, string newGroupSerial)
{
var allLevelTriggers = LevelTriggerChannels.Values.ToArray();
LevelTriggerChannels.Clear();
foreach (var lt in allLevelTriggers)
{
var key = GetLTKey(lt);
var tokens = key.Split('x');
if (tokens.Length < 3) continue;//invalid
if (tokens[0] == oldGroupSerial)
{
lt.GroupChannelId = lt.GroupChannelId.Replace(oldGroupSerial, newGroupSerial);
tokens[0] = newGroupSerial;
tokens[1] = tokens[1].Replace(oldGroupSerial, newGroupSerial);
}
LevelTriggerChannels[string.Join("x", tokens)] = lt;
}
}
/// <summary>
/// updates the channel settings for groups which have changed serial numbers [rename/clone group]
/// 8404 Copy all channel parameters/settings/level triggers/graphs when cloning a test setup
/// </summary>
/// <param name="oldIdToNewIdLookup"></param>
/// <param name="oldGroupSnToNewGroupSn"></param>
public void ReplaceChannelSetting(Dictionary<string, string> oldIdToNewIdLookup, Dictionary<string, string> oldGroupSnToNewGroupSn)
{
using (var e = oldGroupSnToNewGroupSn.GetEnumerator())
{
while (e.MoveNext())
{
lock (SensorLock)
{
if (SensorLookup.ContainsKey(e.Current.Key))
{
var lookup = SensorLookup[e.Current.Key];
SensorLookup[e.Current.Value] = lookup;
}
}
}
}
}
public void ReplaceLevelTriggerChannel(Dictionary<string, string> oldIdToNewIdLookup, Dictionary<string, string> oldGroupSnToNewGroupSn)
{
var itemsToUpdate = new List<string>();
using (var e = LevelTriggerChannels.GetEnumerator())
{
while (e.MoveNext())
{
if (!oldIdToNewIdLookup.ContainsKey(e.Current.Value.GroupChannelId)) continue;
e.Current.Value.GroupChannelId = oldIdToNewIdLookup[e.Current.Value.GroupChannelId];
itemsToUpdate.Add(e.Current.Key);
}
}
foreach (var item in itemsToUpdate)
{
var original = LevelTriggerChannels[item];
LevelTriggerChannels.Remove(item);
LevelTriggerChannels[GetLTKey(original)] = original;
}
}
public void RenameLevelTriggerChannels(string oldName, string newName)
{
var itemsToUpdate = new List<string>();
using (var e = LevelTriggerChannels.GetEnumerator())
{
while (e.MoveNext())
{
if (!e.Current.Value.GroupChannelId.StartsWith(oldName)) continue;
e.Current.Value.GroupChannelId = e.Current.Value.GroupChannelId.Replace(oldName, newName);
itemsToUpdate.Add(e.Current.Key);
}
}
foreach (var item in itemsToUpdate)
{
var original = LevelTriggerChannels[item];
LevelTriggerChannels.Remove(item);
LevelTriggerChannels[GetLTKey(original)] = original;
}
}
public void RemoveImpossibleLevelTriggers()
{
if (0 == LevelTriggerChannels.Count) { return; }
var hardwareChannelLookup = new Dictionary<string, HardwareChannel>();
var dasAlreadyProcessed = new Dictionary<string, bool>();
//var groupChannelIdLookup = new Dictionary<string, TestObjectChannel>();
var groupChannelIdLookup = new Dictionary<long, IGroupChannel>();
var sensorLookup = new Dictionary<int, ISensorData>();
var hardwareLookup = new Dictionary<int, IDASHardware>();
var sensors = SensorsCollection.SensorsList.GetAllSensors(false);
foreach (var s in sensors)
{
sensorLookup[s.DatabaseId] = s;
}
var hardware = DASHardwareList.GetAllHardware();
foreach (var h in hardware)
{
hardwareLookup[h.DASId] = h;
}
var channelDefaults = DbOperations.GetChannelSettingDefaults();
foreach (var group in Groups)
{
//FB 18875 use the hardware list instead of query them on each loop iteration
foreach (var h in hardware.Where(hw => group.IncludedHardware.Contains(hw.DASId)))
{
if (dasAlreadyProcessed.ContainsKey(h.SerialNumber)) continue;
dasAlreadyProcessed.Add(h.SerialNumber, true);
foreach (var ch in h.Channels)
{
hardwareChannelLookup[ch.GetId()] = ch;
}
}
foreach (var ch in group.GetAllChannels(false, sensorLookup, hardwareLookup, channelDefaults))
{
if (!string.IsNullOrWhiteSpace(ch.Sensor) && !string.IsNullOrWhiteSpace(ch.Hardware))
{
groupChannelIdLookup[ch.Id] = ch;
}
}
}
var invalidLTs = new List<LevelTriggerChannel>();
foreach (var ltc in LevelTriggerChannels)
{
var lt = ltc.Value;
//we shouldn't get here but if we do, don't die
if (null == lt.GroupChannel) { continue; }
if (!groupChannelIdLookup.ContainsKey(lt.GroupChannel.Id))
{
invalidLTs.Add(lt);
}
else if (!hardwareChannelLookup.ContainsKey(lt.HardwareChannelId))
{
invalidLTs.Add(lt);
}
else
{
//check that the sensor is valid
if (null != groupChannelIdLookup[lt.GroupChannel.Id].SensorData)
{
var sd = groupChannelIdLookup[lt.GroupChannel.Id].SensorData;
if (!SensorConstants.IsTestSpecificEmbedded(sd.SerialNumber) && lt.SensorSerialNumber != sd.SerialNumber)
{
APILogger.Log($"Eliminated level trigger for channel as {lt.SensorSerialNumber} is no longer the sensor on the channel");
invalidLTs.Add(lt);
}
}
//check that the hardware is the same
var groupChannel = groupChannelIdLookup[lt.GroupChannel.Id];
if ((groupChannel.DASId != lt.GroupChannel.DASId || groupChannel.DASChannelIndex != lt.GroupChannel.DASChannelIndex)
&& !invalidLTs.Contains(lt))
{
APILogger.Log($"Eliminated level trigger as hardware [{lt.HardwareChannelId}] is no longer valid");
invalidLTs.Add(lt);
}
}
}
foreach (var invalid in invalidLTs) { RemoveLevelTrigger(invalid); }
}
#endregion LEVEL_TRIGGER
#region Sensor
/// <summary>
/// get sensor from sensor db again (but preserving custom values such as range/polarity/CFC/etc)
/// note, test objects already get sensors from from db every time. we hold onto them here, I guess for efficiency, but we could get them fresh every time as well
/// </summary>
public void RefreshSensorsFromDb()
{
lock (SensorLock)
{
//MarkIsCompleteUnchecked();
SensorLookup.Clear();
if (string.IsNullOrEmpty(Name)) return;
using (var cmd = DbOperations.GetSQLCommand(true))
{
try
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_TestChannelSettingsGet.ToString();
cmd.Parameters.Add(new SqlParameter("@TestSetupName", SqlDbType.NVarChar) { Value = Name });
cmd.Parameters.Add(new SqlParameter("@TestObjectName", SqlDbType.NVarChar) { Value = null });
cmd.Parameters.Add(new SqlParameter("@ChannelId", SqlDbType.NVarChar) { Value = null });
//cmd.ExecuteNonQuery();
using (var ds2 = DbOperations.Connection.QueryDataSet(cmd))
{
if (ds2.Tables.Count <= 0 || ds2.Tables[0].Rows.Count <= 0) return;
var cFields = Enum.GetValues(typeof(DbOperations.TestSetups.ChannelSettingFields))
.Cast<DbOperations.TestSetups.ChannelSettingFields>().ToArray();
foreach (DataRow row in ds2.Tables[0].Rows)
{
string testobjectname = null;
string channelname = null;
string sensorserial = null;
string setting = null;
var disabled = false;
foreach (var cf in cFields)
{
switch (cf)
{
case DbOperations.TestSetups.ChannelSettingFields.TestName: break;
case DbOperations.TestSetups.ChannelSettingFields.Setting:
setting = row[cf.ToString()] as string;
break;
case DbOperations.TestSetups.ChannelSettingFields.TestObjectName:
testobjectname = row[cf.ToString()] as string;
break;
case DbOperations.TestSetups.ChannelSettingFields.ChannelId:
channelname = row[cf.ToString()] as string;
break;
case DbOperations.TestSetups.ChannelSettingFields.SensorSerial:
sensorserial = row[cf.ToString()] as string;
break;
case DbOperations.TestSetups.ChannelSettingFields.Disabled:
disabled = Convert.ToBoolean(row[cf.ToString()]);
break;
}
}
SetDisabled(testobjectname, channelname, disabled);
if (string.IsNullOrEmpty(testobjectname) || string.IsNullOrEmpty(channelname) ||
string.IsNullOrEmpty(setting)) continue;
try
{
var sd = TestTemplateList.GetSensorFromSettings(setting, sensorserial);
if (null != sd && sd.FilterClassIso == "?")
{
sd.FilterClassIso = "P"; // "Prefiltered > CFC 1000" (Unfiltered)
}
if (null != sd)
{
SetSensor(sd, testobjectname, channelname);
}
}
catch (Exception ex)
{
APILogger.Log("failed to retreive sensor, ", ex);
}
}
}
}
finally
{
cmd.Connection.Dispose();
}
}
}
}
/// <summary>
/// sets a channel to be disabled
/// disabled channels don't appear in run test
/// </summary>
/// <param name="groupName"></param>
/// <param name="channelName"></param>
/// <param name="disabled"></param>
public void SetDisabled(string groupName, string channelName, bool disabled)
{
var matches = from g in TestObjects where g.SerialNumber == groupName select g;
if (!matches.Any()) return;
var iso = matches.First().GetISOTestObject();
var allChannels = iso.AllChannels;
foreach (var ch in allChannels)
{
if (ch.Name == channelName)
{
ch.Disabled = disabled;
break;
}
}
}
public SensorData GetSensor(IGroupChannel groupChannel, IReadOnlyDictionary<string, SensorCalibration> calLookup = null)
{
//FB 18875 added cached sensor calibration
var sd = SensorsCollection.SensorsList.GetSensorById(groupChannel.SensorId, true, calLookup);
return (SensorData)groupChannel.Group.GetSensor(groupChannel, sd, SerializedSettings.UseISOCodeFilterMapping);
}
public SensorData GetSensor(string serialNumber, string testObjectSerial, string channelName)
{
lock (SensorLock)
{
var tto = GetTestTestObject(testObjectSerial);
if (SensorLookup.ContainsKey(testObjectSerial))
{
if (SensorLookup[testObjectSerial].ContainsKey(channelName))
{
if (SensorLookup[testObjectSerial][channelName].ContainsKey(serialNumber))
{
if (SensorLookup[testObjectSerial][channelName][serialNumber].FilterClassIso == "?")
{
SensorLookup[testObjectSerial][channelName][serialNumber].FilterClassIso =
"P"; // "Prefiltered > CFC 1000" (Unfiltered)
}
//for some reason the Filter isn't always set, setting filterclassiso will ensure it gets set, even though it should have already _been_ set
SensorLookup[testObjectSerial][channelName][serialNumber].FilterClassIso =
SensorLookup[testObjectSerial][channelName][serialNumber].FilterClassIso;
if (null == tto)
{
return new SensorData(SensorLookup[testObjectSerial][channelName][serialNumber]);
}
var position = tto.Position.Position;
if (position != TestTestObject.UserSetKey &&
position != TestTestObject.ChannelDefaultsKey &&
position != SensorLookup[testObjectSerial][channelName][serialNumber].Position)
{
SensorLookup[testObjectSerial][channelName][serialNumber].Position = position;
}
return new SensorData(SensorLookup[testObjectSerial][channelName][serialNumber]);
}
}
}
if (null == tto)
{
return new SensorData(SensorsCollection.SensorsList.GetSensorBySerialNumber(serialNumber));
}
var ttosd = tto.GetSensor(channelName, serialNumber);
if (ttosd != null)
{
ttosd.TestObject = tto.TestObject.Test_Object;
var position = tto.Position.Position;
if (position != TestTestObject.UserSetKey &&
position != TestTestObject.ChannelDefaultsKey &&
position != ttosd.Position)
{
ttosd.Position = position;
}
}
else
{
return null;
}
return new SensorData(ttosd);
}
}
// FB5438 & FB5023
public void RemoveSensor(string sensorserialnumber, string testobjectserial, string channelname)
{
lock (SensorLock)
{
if (SensorLookup.ContainsKey(testobjectserial)
&& SensorLookup[testobjectserial].ContainsKey(channelname)
&& SensorLookup[testobjectserial][channelname].ContainsKey(sensorserialnumber))
{
SensorLookup[testobjectserial][channelname].Remove(sensorserialnumber);
}
}
}
/// <summary>
/// sets a sensor in the lookup for this test setup, however preserves any existing settings for that sensor
/// this is done because we want to preserve the range and other custom settings for a test setup, but do want to
/// get any of the non customizable information (like capacity and sensitivity) updated in the copy in memory.
/// </summary>
/// <param name="sd"></param>
/// <param name="testobjectserial"></param>
/// <param name="channelname"></param>
public void SetSensorWithoutChangingSettings(SensorData sd, string testobjectserial, string channelname)
{
var sdOld = GetSensor(sd.SerialNumber, testobjectserial, channelname);
var settings = TestTemplateList.GetSensorSettings(sdOld);
sd = TestTemplateList.GetSensorFromSettings(settings, sd.SerialNumber);
SetSensor(sd, testobjectserial, channelname);
}
public void SetSensor(SensorData sd, string testobjectserial, string channelname)
{
SetSensor(sd, testobjectserial, channelname, false);
}
private static readonly object SensorLock = new object();
/// <summary>
/// sets the sensor (and custom values like range/CFC/polarity) for a channel in the test
/// </summary>
/// <param name="sd"></param>
/// <param name="testobjectserial"></param>
/// <param name="channelname"></param>
/// <param name="bSetPositionFromSensor"></param>
public void SetSensor(SensorData sd, string testobjectserial, string channelname, bool bSetPositionFromSensor)
{
lock (SensorLock)
{
if (!SensorLookup.ContainsKey(testobjectserial))
{
SensorLookup.Add(testobjectserial, new Dictionary<string, Dictionary<string, SensorData>>());
}
if (!SensorLookup[testobjectserial].ContainsKey(channelname))
{
SensorLookup[testobjectserial].Add(channelname, new Dictionary<string, SensorData>());
}
//Build out the ISO fields we know about
// FB 5423
var tto = GetTestTestObject(testobjectserial) ?? new TestTestObject(new TestObject());
sd.TestObject = tto.TestObject.Test_Object;
// ReSharper disable once InconsistentNaming
var isoTO = tto.GetISOTestObject();
var channel = isoTO.GetChannel(channelname);
if (bSetPositionFromSensor)
{
if (tto.Position.Position != sd.Position && tto.Position.Position != TestTestObject.UserSetKey)
{
tto.SetPosition(TestTestObject.UserSetKey);
}
}
else
{
if ((tto.Position.Position != TestTestObject.ChannelDefaultsKey) && //Remove this?
(tto.Position.Position != TestTestObject.UserSetKey))
{
sd.Position = tto.Position.Position;
}
}
if (null != channel)
{
sd.FineLocation1 = channel.Channel.Fine_Loc_1;
sd.FineLocation2 = channel.Channel.Fine_Loc_2;
sd.FineLocation3 = channel.Channel.Fine_Loc_3;
sd.MainLocation = channel.Channel.Trans_Main_Loc;
sd.PhysicalDimension = channel.Channel.Physical_Dimension;
sd.Direction = channel.Channel.Direction;
}
SensorLookup[testobjectserial][channelname][sd.SerialNumber] = sd;
}
}
public void ReplaceSensorsInLookup(TestTestObject group, string oldName, string newName)
{
foreach (var ch in group.GetISOTestObject().AllChannels)
{
if (ch.Required)
{
var sd = GetSensor(ch.SensorSerialNumber, group.SerialNumber.Replace(newName, oldName), ch.Name);
if (sd == null) continue;
SetSensor(sd, group.SerialNumber, ch.Name);
RemoveSensor(sd.SerialNumber, group.SerialNumber.Replace(newName, oldName), ch.Name);
}
}
}
#endregion Sensor
#region XML
#region READING FROM XML
/// <summary>
/// reads a test template node from xml
/// if we are doing an import, some objects like test objects, customers, and labs are also going to be in the import
/// and not in the db yet
/// </summary>
/// <param name="root">node to process</param>
/// <param name="testObjectLookup"></param>
/// <param name="labLookup"></param>
/// <param name="customerLookup"></param>
/// <param name="testEngineerLookup"></param>
/// <param name="sensorLookup"></param>
public void ReadXML(System.Xml.XmlElement root,
Dictionary<string, TestObject> testObjectLookup,
Dictionary<string, IGroup> groupLookup,
Dictionary<string, DTS.Common.ISO.LabratoryDetails> labLookup,
Dictionary<string, DTS.Common.ISO.CustomerDetails> customerLookup,
Dictionary<string, DTS.Common.ISO.TestEngineerDetails> testEngineerLookup,
Dictionary<string, SensorData> sensorLookup,
List<DASHardware> hardware,
List<SensorCalibration> sensorCalibrations)
{
var allHardware = DASHardwareList.GetAllHardware();
var hwlookup = new Dictionary<int, IDASHardware>();
foreach (var h in allHardware) { hwlookup[h.DASId] = h; }
//gets a list of channel defaults from the db
//the import will override with any specific settings
//would cause issues with the channel display in BasicInfo with
//16117 Sensors and groups tables not populated when using recovery controls feature in download tab
//otherwise with missing settings
var channelDefaults = DbOperations.GetChannelSettingDefaults();
foreach (var node in root.ChildNodes)
{
if (!(node is System.Xml.XmlElement child)) { continue; }
switch (child.Name)
{
//15727 Building and Replacing Racks/Mods
case TESTID_ROOT: //first started in version 9
{
if (int.TryParse(child.InnerText, out var id))
{
Id = id;
}
}
break;
case DASLIST_ROOT://first started in version 4
{
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement) { ProcessDASHardwareNode(sub as System.Xml.XmlElement); }
}
}
break;
case GROUPS_ROOT: //Groups first started in Version 3
{
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement) { ProcessGroupNode(sub as System.Xml.XmlElement, groupLookup, sensorLookup, channelDefaults, sensorCalibrations); }
}
}
break;
case GRAPHS_ROOT:
{
var lookup = new Dictionary<long, IGroupChannel>();
foreach (var group in Groups)
{
var channels = ChannelsForGroup[group];
foreach (var channel in channels)
{
lookup[channel.Id] = channel;
}
}
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement)
{
ProcessGraphs(sub as System.Xml.XmlElement, lookup);
}
}
}
break;
case FIELDS_ROOT:
{
var channelLookup = new Dictionary<long, IGroupChannel>();
foreach (var group in Groups)
{
var channels = ChannelsForGroup[group];
foreach (var channel in channels)
{
channelLookup[channel.Id] = channel;
}
}
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement)
{
ProcessFields(sub as System.Xml.XmlElement, customerLookup, testEngineerLookup, labLookup,
sensorLookup, hardware, channelLookup);
}
}
}
break;
case METADATAS_ROOT:
{
ProcessMetaDatas(child);
}
break;
case HARDWAREOVERRIDES_ROOT://no longer used in version 3
{
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement) { ProcessHardwareOverrides(sub as System.Xml.XmlElement); }
}
}
break;
case HARDWAREINCLUDES_ROOT://first started in version 3
{
var s = child.GetAttribute(HARDWARELIST_ROOT);
var tokens = s.Split(',');
foreach (var token in tokens)
{
var id = Convert.ToInt32(token, CultureInfo.InvariantCulture);
AddHardware(id, hwlookup);
}
}
break;
case HARDWAREREMOVES_ROOT://first started in version 3
{
var s = child.GetAttribute(HARDWARELIST_ROOT);
var tokens = s.Split(',');
foreach (var token in tokens)
{
var id = Convert.ToInt32(token, CultureInfo.InvariantCulture);
RemoveHardware(id, allHardware, hwlookup);
}
}
break;
case LEVELTRIGGERS_ROOT:
{
var lookup = new Dictionary<long, IGroupChannel>();
foreach (var group in Groups)
{
var channels = ChannelsForGroup[group];
foreach (var channel in channels)
{
lookup[channel.Id] = channel;
}
}
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement) { ProcessLevelTriggers(sub as System.Xml.XmlElement, lookup); }
}
}
break;
case CALCULATEDCHANNELS_ROOT:
{
var lookup = new Dictionary<long, IGroupChannel>();
foreach (var group in Groups)
{
var channels = ChannelsForGroup[group];
foreach (var channel in channels)
{
lookup[channel.Id] = channel;
}
}
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement) { ProcessCalculatedChannels(sub as System.Xml.XmlElement, lookup); }
}
}
break;
case TSRAIRSETTINGS_ROOT:
ReadTSRAirSettings(child);
break;
default: throw new NotSupportedException("TestTemplate::ReadXML unsupported field: " + child.Name);
}
}
}
/// <summary>
/// reads a test template node from xml
/// if we are doing an import, some objects like test objects, customers, and labs are also going to be in the import
/// and not in the db yet
/// </summary>
/// <param name="root">node to process</param>
/// <param name="testObjectLookup"></param>
/// <param name="labLookup"></param>
/// <param name="customerLookup"></param>
/// <param name="testEngineerLookup"></param>
/// <param name="sensorLookup"></param>
public void ReadXMLPre20(System.Xml.XmlElement root,
Dictionary<string, TestObject> testObjectLookup,
Dictionary<string, DTS.Common.ISO.LabratoryDetails> labLookup,
Dictionary<string, DTS.Common.ISO.CustomerDetails> customerLookup,
Dictionary<string, DTS.Common.ISO.TestEngineerDetails> testEngineerLookup,
Dictionary<string, SensorData> sensorLookup,
List<DASHardware> hardware)
{
foreach (var node in root.ChildNodes)
{
if (!(node is System.Xml.XmlElement child)) { continue; }
switch (child.Name)
{
case TESTOBJECTS_ROOT:
{
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement) { ProcessTestObjectNode(sub as System.Xml.XmlElement, testObjectLookup, sensorLookup); }
}
}
break;
case ADDEDGROUPS_ROOT:
case SYSBUILTTESTOBJECTS_ROOT:
{
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement) { ProcessAddedGroupsPre20(sub as System.Xml.XmlElement, testObjectLookup, sensorLookup); }
}
}
break;
case GRAPHS_ROOT:
{
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement) { ProcessGraphsPre20(sub as System.Xml.XmlElement); }
}
}
break;
case FIELDS_ROOT:
{
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement)
{
ProcessFields(sub as System.Xml.XmlElement, customerLookup, testEngineerLookup, labLookup,
sensorLookup, hardware, null);
}
}
}
break;
case METADATAS_ROOT:
{
ProcessMetaDatas(child);
}
break;
case HARDWAREOVERRIDES_ROOT:
{
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement) { ProcessHardwareOverrides(sub as System.Xml.XmlElement); }
}
}
break;
case LEVELTRIGGERS_ROOT:
{
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement) { ProcessLevelTriggersPre20(sub as System.Xml.XmlElement); }
}
}
break;
case CALCULATEDCHANNELS_ROOT:
{
foreach (var sub in child.ChildNodes)
{
if (sub is System.Xml.XmlElement) { ProcessCalculatedChannelsPre20(sub as System.Xml.XmlElement); }
}
}
break;
default: throw new NotSupportedException("TestTemplate::ReadXML unsupported field: " + child.Name);
}
}
}
/// <summary>
/// processes a test setup meta data node from xml
/// </summary>
/// <param name="root"></param>
private void ProcessMetaDatas(System.Xml.XmlElement root)
{
try
{
var fields = Enum.GetValues(typeof(DbOperations.TestSetups.TestObjectMetaDataFields))
.Cast<DbOperations.TestSetups.TestObjectMetaDataFields>().ToArray();
foreach (var child in root.ChildNodes)
{
if (!(child is System.Xml.XmlElement node)) { continue; }
var values = new Dictionary<DbOperations.TestSetups.TestObjectMetaDataFields, string>();
foreach (var field in fields)
{
values[field] = node.GetAttribute(field.ToString()).Trim();
}
// FB 17951 Prevent empty TestObject process
var testObject = values[DbOperations.TestSetups.TestObjectMetaDataFields.TestObject];
if (string.IsNullOrWhiteSpace(testObject))
{
continue;
}
else if ("_" == testObject)
{
var meta = GetTestMetaData();
if (!Enum.TryParse(values[DbOperations.TestSetups.TestObjectMetaDataFields.PropName], out TestSetupMetaData.Fields field)) continue;
meta.SetPropertyValue(field, values[DbOperations.TestSetups.TestObjectMetaDataFields.PropValue]);
System.Diagnostics.Trace.WriteLine("Set " + field + " to " + values[DbOperations.TestSetups.TestObjectMetaDataFields.PropValue]);
}
else
{
var meta = GetMetaData(values[DbOperations.TestSetups.TestObjectMetaDataFields.TestObject].First());
meta.SetPropertyValue(values[DbOperations.TestSetups.TestObjectMetaDataFields.PropName], values[DbOperations.TestSetups.TestObjectMetaDataFields.PropValue]);
}
}
}
catch (Exception ex)
{
APILogger.Log("ProcessMetaDatas: ", ex);
throw;
}
}
private CalibrationBehaviors ParseCalibrationBehavior(string txt)
{
if (Enum.TryParse(txt, out CalibrationBehaviors calBehavior))
{
return calBehavior;
}
if (txt.ToLower().Equals("alwayslinear")) { return CalibrationBehaviors.LinearIfAvailable; }
throw new Exception($"Calibration setting: {txt} unknown");
}
/// <summary>
/// processes test setup fields from a test setup node in xml
/// </summary>
/// <param name="node"></param>
/// <param name="customerLookup"></param>
/// <param name="testEngineerLookup"></param>
/// <param name="labLookup"></param>
private void ProcessFields(System.Xml.XmlElement node
, Dictionary<string, DTS.Common.ISO.CustomerDetails> customerLookup
, Dictionary<string, DTS.Common.ISO.TestEngineerDetails> testEngineerLookup,
Dictionary<string, DTS.Common.ISO.LabratoryDetails> labLookup,
Dictionary<string, SensorData> sensorLookup,
List<DASHardware> hardware,
Dictionary<long, IGroupChannel> channelLookup)
{
if (Enum.TryParse(node.Name, out DbOperations.TestSetups.Fields field))
{
switch (field)
{
case DbOperations.TestSetups.Fields.AllowMissingSensors: AllowMissingSensors = bool.Parse(node.InnerText); break;
case DbOperations.TestSetups.Fields.AllowSensorIdToBlankChannel: AllowSensorIdToBlankChannel = bool.Parse(node.InnerText); break;
case DbOperations.TestSetups.Fields.AutomaticProgressionDelayMS: AutomaticProgressionDelayMS = int.Parse(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.Fields.AutomaticTestProgression: AutomaticProgression = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.AutoVerifyChannels: AutoVerifyChannels = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.CalibrationBehavior: CalibrationBehavior = ParseCalibrationBehavior(node.InnerText); break;
case DbOperations.TestSetups.Fields.CommonStatusLine: CommonLine = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.CustomerDetails:
{
if (!string.IsNullOrWhiteSpace(node.InnerText))
{
CustomerDetails = customerLookup.ContainsKey(node.InnerText) ? new CustomerDetails(customerLookup[node.InnerText])
: CustomerDetailsList.GetCustomerDetail(node.InnerText);
}
}
break;
case DbOperations.TestSetups.Fields.TestEngineerDetails:
{
if (!string.IsNullOrWhiteSpace(node.InnerText))
{
TestEngineerDetails = testEngineerLookup.ContainsKey(node.InnerText) ? new TestEngineerDetails(testEngineerLookup[node.InnerText])
: TestEngineerDetailsList.TestEngineerList.GetTestEngineerDetail(node.InnerText);
}
}
break;
case DbOperations.TestSetups.Fields.DownloadAll: DownloadAll = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.DownloadFolder:
{
var downloadFolder = node.InnerText;
if (downloadFolder == @"..\Data")
{
downloadFolder = @"..\..\Data";
}
DownloadFolder = downloadFolder;
}
break;
case DbOperations.TestSetups.Fields.Export: ViewExport = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.ExportFolder:
{
var exportFolder = node.InnerText;
if (exportFolder == @"..\Data")
{
exportFolder = @"..\..\Data";
}
ExportFolder = exportFolder;
}
break;
case DbOperations.TestSetups.Fields.ExportFormat: ExportFormats = (SupportedExportFormatBitFlags)Convert.ToUInt64(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.Fields.InvertStart: InvertStartRecordCompletion = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.InvertTrigger: InvertTriggerCompletion = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.IgnoreShortedStart: IgnoreShortedStartCompletion = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.IgnoreShortedTrigger: IgnoreShortedTriggerCompletion = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.LabDetails:
{
if (!string.IsNullOrWhiteSpace(node.InnerText))
{
LabDetails = labLookup.ContainsKey(node.InnerText) ? new LabratoryDetails(labLookup[node.InnerText])
: LabratoryDetailsList.GetLab(node.InnerText);
}
}
break;
case DbOperations.TestSetups.Fields.LastModified: LastModified = DateTime.Parse(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.Fields.LastModifiedBy: LastModifiedBy = node.InnerText; break;
case DbOperations.TestSetups.Fields.LocalOnly: LocalOnly = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.PostTestDiagnostics: PostTestDiagnosticsLevel = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.PostTriggerSeconds: PostTriggerSeconds = Convert.ToDouble(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.Fields.PreTriggerSeconds: PreTriggerSeconds = Convert.ToDouble(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.Fields.NumberOfEvents: NumberOfEvents = Convert.ToInt32(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.Fields.WakeUpMotionTimeout: WakeUpMotionTimeout = Convert.ToInt32(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.Fields.ScheduledStartDateTime: RTCScheduleStartDateTime = Convert.ToDateTime(node.InnerText, System.Globalization.CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.Fields.IntervalBetweenEventStartsMinutes: IntervalBetweenEventStartsMinutes = Convert.ToInt32(node.InnerText, System.Globalization.CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.Fields.StartWithEvent: StartWithEvent = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.WakeUpWithMotion: WakeUpWithMotion = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.RealtimePlotCount: DefaultNumberRealtimeGraphs = Convert.ToInt32(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.Fields.RecordingMode: RecordingMode = (RecordingModes)Enum.Parse(typeof(RecordingModes), node.InnerText); break;
case DbOperations.TestSetups.Fields.RequireConfirmationOnErrors: RequireUserConfirmationOnErrors = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.RegionsOfInterest:
RegionsOfInterest.Clear();
foreach (System.Xml.XmlElement childNode in node.ChildNodes)
{
try
{
var roi = new RegionOfInterest(
childNode.GetElementsByTagName("Suffix")[0].InnerText,
true,
Convert.ToDouble(childNode.GetElementsByTagName("Start")[0].InnerText,
CultureInfo.InvariantCulture),
Convert.ToDouble(childNode.GetElementsByTagName("End")[0].InnerText,
CultureInfo.InvariantCulture));
var channelNames = childNode.GetElementsByTagName("ChannelNames")[0]?.InnerText.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
var channelNameList = new List<string>();
if (null == channelNames)
{
APILogger.Log("Warning: TestTemplate.ProcessFields has null for channelNames");
}
else
{
foreach (var channelName in channelNames)
{
var newChannelName = channelName;
if (!channelName.StartsWith("[") && !channelName.StartsWith("\\"))
{
//Since there is no hardware associated, see if there should be (it's OK if not).
newChannelName = AddHardwareToImportedChannelIfAssigned(channelName, sensorLookup, hardware);
}
channelNameList.Add(newChannelName);
}
}
roi.ChannelNames = channelNameList.ToArray();
if (channelLookup != null)
{
var channelIds = childNode.GetElementsByTagName("ChannelIds")[0]?.InnerText.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
var channelIdList = new List<long>();
if (null == channelIds)
{
APILogger.Log("Warning: TestTemplate.ProcessFields has null for channelIds");
}
else
{
foreach (var channelId in channelIds)
{
channelIdList.Add(Convert.ToInt64(channelId));
}
}
roi.ChannelIds = channelIdList.ToArray();
}
RegionsOfInterest.Add(roi);
}
catch (Exception e)
{
APILogger.Log("Error processing ROI XML");
APILogger.LogException(e);
}
}
if (RegionsOfInterest.Count == 0)
{
RegionsOfInterest.Add(new RegionOfInterest(true));
}
break;
case DbOperations.TestSetups.Fields.ROIDownload: DoROIDownload = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.ROIEnd: ROIEnd = Convert.ToDouble(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.Fields.ROIStart: ROIStart = Convert.ToDouble(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.Fields.SameAsDownloadFolder: SameAsDownloadFolder = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.SamplesPerSecond:
//If we find a possible bad export that had set SamplesPerSecond to "NaN", set SamplesPerSecondAggregate to the default
if (node.InnerText == "NaN") //Double.TryParse will not return false if "NaN" is passed
{
SamplesPerSecondAggregate = Defaults.GetUserSettingValueDouble(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.DefaultTestSampleRate);
}
else
{
SamplesPerSecondAggregate = Convert.ToDouble(node.InnerText, CultureInfo.InvariantCulture);
}
//Make a list of SerialNumbers of DAS in the Test Setup so we don't stomp on their sample rates
var testSetupDASList = new List<string>();
foreach (var h in hardware)
{
testSetupDASList.Add(h.SerialNumber);
}
//Make a list of SerialNumbers of DAS that are not in the Test Setup.
var nonTestSetupDASList = new List<string>();
foreach (var dasRatePair in DASSampleRateList)
{
if (!testSetupDASList.Contains(dasRatePair.Key))
{
nonTestSetupDASList.Add(dasRatePair.Key);
}
}
//16285 Significant delay using the download data tile
//this allows us to retrieve all DAS once and then avoid re-retrieving them in the loop
//below
var allDAS = DASHardwareList.GetAllHardware();
var lookup = new Dictionary<string, DASHardware>();
foreach (var d in allDAS) { lookup[d.SerialNumber] = d; }
//Set all DAS that are not in the Test Setup to the Test Setup sample rate in case they are added later.
foreach (var nonTestSetupDAS in nonTestSetupDASList)
{
DASSampleRateList[nonTestSetupDAS] = SamplesPerSecondAggregate;
//FB15759: if we don't know about the DAS yet, mark freq 0 and we'll fix later
DASAAFRateList[nonTestSetupDAS] = lookup.ContainsKey(nonTestSetupDAS)
? GetAAFForHardware(lookup[nonTestSetupDAS], (int)SamplesPerSecondAggregate)
: 0;
}
break;
case DbOperations.TestSetups.Fields.SetupDescription: Description = node.InnerText; break;
case DbOperations.TestSetups.Fields.WarnOnBatteryFail: WarnOnFailedBattery = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.SetupName: Name = node.InnerText.Trim(); break;
case DbOperations.TestSetups.Fields.Settings: _settings.LoadSettings(node.InnerText); break;
case DbOperations.TestSetups.Fields.StrictDiagnostics: StrictDiagnostics = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.TriggerCheckRealtime: TriggerCheckRealtime = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.TriggerCheckStep: TriggerCheckStep = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.TurnOffExcitation: TurnOffExcitation = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.UploadData: UploadData = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.UploadDataFolder: UploadFolder = node.InnerText; break;
case DbOperations.TestSetups.Fields.UploadExportsOnly: UploadExportsOnly = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.VerifyChannels: VerifyChannels = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.VerifyChannelsDelayMS: AutoVerifyDelaySeconds = Convert.ToDouble(node.InnerText, CultureInfo.InvariantCulture) / 1000D; break;
case DbOperations.TestSetups.Fields.ViewDiagnostics: ViewDiagnostics = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.ViewDownloadAll: ViewDownloadAll = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.ViewRealtime: ViewRealtime = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.ViewROIDownload: ViewROIDownload = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.Complete: SetIsComplete(Convert.ToBoolean(node.InnerText)); break;
case DbOperations.TestSetups.Fields.Dirty: SetIsDirty(Convert.ToBoolean(node.InnerText)); break;
case DbOperations.TestSetups.Fields.ErrorMessage: SetCompletionErrorMessage(node.InnerText); break;
case DbOperations.TestSetups.Fields.UserTags:
SetTagsFromCommaSeparatedString(node.InnerText,
DbOperations.GetSQLCommand, DbOperations.TagsGet, DbOperations.TagsGetId,
DbOperations.TagsInsert); break;
case DbOperations.TestSetups.Fields.DoAutoArm: DoAutoArm = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.DoEnableRepeat: DoEnableRepeat = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.DoStreaming: DoStreaming = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.CheckoutMode: CheckoutMode = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.QuitTestWithoutWarning: QuitTestWithoutWarning = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.SuppressMissingSensorsWarning: SuppressMissingSensorsWarning = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.NotAllChannelsViewer: NotAllChannelsViewer = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.NotAllChannelsRealTime: NotAllChannelsRealTime = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.ClockSyncProfileMaster: ClockSyncProfileMaster = (ClockSyncProfile)Enum.Parse(typeof(ClockSyncProfile), node.InnerText); break;
case DbOperations.TestSetups.Fields.ClockSyncProfileSlave: ClockSyncProfileSlave = (ClockSyncProfile)Enum.Parse(typeof(ClockSyncProfile), node.InnerText); break;
case DbOperations.TestSetups.Fields.ISFFile: ISFFile = node.InnerText; break;
case DbOperations.TestSetups.Fields.ExtraProperties:
ExtraProperties.Clear();
foreach (System.Xml.XmlElement childNode in node.ChildNodes)
{
try
{
ExtraProperties.Add(new ExtraProperty()
{
Key = childNode.GetElementsByTagName("Key")[0].InnerText,
Value = childNode.GetElementsByTagName("Value")[0].InnerText
});
}
catch (Exception e)
{
APILogger.Log("Error processing Extra Properties XML");
APILogger.LogException(e);
}
}
break;
case DbOperations.TestSetups.Fields.MeasureSquibResistancesStep: MeasureSquibResistancesStep = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.TestSetupUniqueId: TestSetupUniqueId = node.InnerText.Trim(); break;
case DbOperations.TestSetups.Fields.AlignUDPToPPS: AlignUDPToPPS = Convert.ToBoolean(node.InnerText); break;
case DbOperations.TestSetups.Fields.UseCustomerDetails: break;
case DbOperations.TestSetups.Fields.UseLabDetails: break;
case DbOperations.TestSetups.Fields.UseTestEngineerDetails: break;
default:
throw new NotSupportedException("TestTemplate::ProcessFields unsupported field: " + field);
}
}
else
{
if (node.Name == "TestId")
{
TestId = node.InnerText;
}
else
{
var err = "TestTemplate::ProcessFields unsupported field: " + node.Name;
APILogger.Log(err);
throw new NotSupportedException(err);
}
}
}
/// <summary>
/// processes graphs from a test setup node xml
/// </summary>
/// <param name="node"></param>
private void ProcessGraphs(System.Xml.XmlElement node, IReadOnlyDictionary<long, IGroupChannel> channelLookup)
{
var graphs = new List<TestGraph>(TestGraphs);
var g = new TestGraph();
g.ReadXML(node, channelLookup);
graphs.Add(g);
TestGraphs = graphs.ToArray();
}
/// <summary>
/// processes graphs from a test setup node xml
/// </summary>
/// <param name="node"></param>
private void ProcessGraphsPre20(System.Xml.XmlElement node)
{
var graphs = new List<TestGraph>(TestGraphs);
var g = new TestGraph(this);
foreach (var child in node.ChildNodes)
{
if (child is System.Xml.XmlElement)
{
var element = child as System.Xml.XmlElement;
if (!Enum.TryParse(element.Name, out DbOperations.TestSetups.GraphFields field)) continue;
switch (field)
{
case DbOperations.TestSetups.GraphFields.Channels:
g.SetChannelsFromSQL(element.InnerText);
break;
case DbOperations.TestSetups.GraphFields.DomainMax:
{
if (double.TryParse(element.InnerText, NumberStyles.Any,
CultureInfo.InvariantCulture, out var d))
{
g.DomainMax = d;
}
}
break;
case DbOperations.TestSetups.GraphFields.DomainMin:
{
if (double.TryParse(element.InnerText, NumberStyles.Any,
CultureInfo.InvariantCulture, out var d))
{
g.DomainMin = d;
}
}
break;
case DbOperations.TestSetups.GraphFields.GraphDescription: g.GraphDescription = element.InnerText; break;
case DbOperations.TestSetups.GraphFields.GraphName: g.GraphName = element.InnerText; break;
case DbOperations.TestSetups.GraphFields.LocalOnly: break;
case DbOperations.TestSetups.GraphFields.RangeMax:
{
if (double.TryParse(element.InnerText, NumberStyles.Any,
CultureInfo.InvariantCulture, out var d))
{
g.RangeMax = d;
}
}
break;
case DbOperations.TestSetups.GraphFields.RangeMin:
{
if (double.TryParse(element.InnerText, NumberStyles.Any,
CultureInfo.InvariantCulture, out var d))
{
g.RangeMin = d;
}
}
break;
case DbOperations.TestSetups.GraphFields.TemplateName: break;
case DbOperations.TestSetups.GraphFields.Thresholds: g.SetThresholdsFromSQL(element.InnerText); break;
case DbOperations.TestSetups.GraphFields.UseDomainMax: g.UseDomainMax = Convert.ToBoolean(element.InnerText); break;
case DbOperations.TestSetups.GraphFields.UseDomainMin: g.UseDomainMin = Convert.ToBoolean(element.InnerText); break;
case DbOperations.TestSetups.GraphFields.UseRangeMax: g.UseRangeMax = Convert.ToBoolean(element.InnerText); break;
case DbOperations.TestSetups.GraphFields.UseRangeMin: g.UseRangeMin = Convert.ToBoolean(element.InnerText); break;
case DbOperations.TestSetups.GraphFields.TestSetupName: break;
default: throw new NotSupportedException("TestTemplate::ProcessGraphs unsupported field: " + field);
}
}
}
graphs.Add(g);
TestGraphs = graphs.ToArray();
}
/// <summary>
/// processes Hardware inclusion instructions (added or removed hardware in test setup)
/// </summary>
/// <param name="node"></param>
private void ProcessHardwareOverrides(System.Xml.XmlElement node)
{
HardwareInclusionInstruction instruction = null;
var action = node.GetAttribute(HARDWAREOVERRIDE_ACTION);
var hid = node.GetAttribute(HARDWAREOVERRIDE_HID);
if (string.IsNullOrWhiteSpace(action) ||
string.IsNullOrWhiteSpace(hid) ||
!Enum.TryParse(action, out HardwareInclusionInstruction.Actions actionEnum))
{
APILogger.Log("problem in import, hardware instruction is invalid: " + node.InnerText);
}
else { instruction = new HardwareInclusionInstruction(hid, actionEnum); }
if (null != instruction) { HardwareOverrides[instruction.HardwareId] = instruction; }
}
private void ProcessCalculatedChannels(System.Xml.XmlElement node, IReadOnlyDictionary<long, IGroupChannel> channelLookup)
{
try
{
var id = int.Parse(node.GetAttribute(CC_ID), CultureInfo.InvariantCulture);
var testSetupName = node.GetAttribute(CC_TESTSETUPNAME);
var operation = (Operations)Enum.Parse(typeof(Operations), node.GetAttribute(CC_OPERATION));
var name = node.GetAttribute(CC_NAME);
var inputChannelIds = node.GetAttribute(CC_INPUTCHANNELIDS).Split(new[] { CultureInfo.InvariantCulture.TextInfo.ListSeparator }, StringSplitOptions.None);
var inputGroupChannelsList = new List<IGroupChannel>();
foreach (var token in inputChannelIds)
{
if (long.TryParse(token, out var l))
{
if (channelLookup.ContainsKey(l))
{
inputGroupChannelsList.Add(channelLookup[l]);
}
}
}
var cfcForOutput = node.GetAttribute(CC_CFCFOROUTPUTCHANNELS);
var cfcInput = node.GetAttribute(CC_CFCFORINPUTCHANNELS);
var calculatedValueCode = node.GetAttribute(CC_CALCULATEDCHANNELVALUE);
bool bViewInRealtime = false;
if( bool.TryParse(node.GetAttribute(CC_VIEWINREALTIME), out var bTemp))
{
bViewInRealtime = bTemp;
}
var clipLength = 0;
if (int.TryParse(node.GetAttribute(CC_CLIPLENGTH), out var iTemp))
{
clipLength = iTemp;
}
var cc = new CalculatedValueClass
{
Id = id,
TestSetupName = testSetupName,
Operation = operation,
Name = name,
InputChannelIds = inputChannelIds,
ChannelFilterClassForOutput = cfcForOutput,
CFCForInputChannels = cfcInput,
CalculatedValueCode = calculatedValueCode,
ViewInRealtime = bViewInRealtime,
ClipLength = clipLength
};
cc.SetChannels(inputGroupChannelsList.ToArray());
CalculatedChannels.Add(cc);
}
catch (Exception ex) { APILogger.Log(ex); }
}
private void ProcessCalculatedChannelsPre20(System.Xml.XmlElement node)
{
try
{
var id = int.Parse(node.GetAttribute(CC_ID), CultureInfo.InvariantCulture);
var testSetupName = node.GetAttribute(CC_TESTSETUPNAME);
var operation = (Operations)Enum.Parse(typeof(Operations), node.GetAttribute(CC_OPERATION));
var name = node.GetAttribute(CC_NAME);
var inputChannelIds = node.GetAttribute(CC_INPUTCHANNELIDS).Split(new[] { CultureInfo.InvariantCulture.TextInfo.ListSeparator }, StringSplitOptions.None);
var cfcForOutput = node.GetAttribute(CC_CFCFOROUTPUTCHANNELS);
var cfcInput = node.GetAttribute(CC_CFCFORINPUTCHANNELS);
var calculatedValueCode = node.GetAttribute(CC_CALCULATEDCHANNELVALUE);
var cc = new CalculatedValueClass
{
Id = id,
TestSetupName = testSetupName,
Operation = operation,
Name = name,
InputChannelIds = inputChannelIds,
ChannelFilterClassForOutput = cfcForOutput,
CFCForInputChannels = cfcInput,
CalculatedValueCode = calculatedValueCode
};
SetCalculatedChannelInputChannelsFromXML(cc);
CalculatedChannels.Add(cc);
}
catch (Exception ex) { APILogger.Log(ex); }
}
public void SetCalculatedChannelInputChannelsFromXML(CalculatedValueClass cc)
{
var lookup = new Dictionary<string, TestObjectChannel>();
if (null == AvailableCalculatedChannelInputChannels)
{
return;
}
foreach (var channel in AvailableCalculatedChannelInputChannels)
{
lookup[channel.GetId()] = channel;
}
var testObjectChannelsList = new List<TestObjectChannel>();
foreach (var sChannel in cc.InputChannelIds)
{
if (lookup.ContainsKey(sChannel))
{
testObjectChannelsList.Add(lookup[sChannel]);
}
}
cc.SetTestObjectChannels(testObjectChannelsList.ToArray());
}
private readonly List<TestObjectChannel> _channels = new List<TestObjectChannel>();
private readonly Dictionary<string, TestObjectChannel> _lookup = new Dictionary<string, TestObjectChannel>();
public TestObjectChannel[] AvailableCalculatedChannelInputChannels
{
get
{
_lookup.Clear();
var channels = new List<TestObjectChannel>();
foreach (var setChannel in _channels)
{
_lookup[setChannel.GetId()] = setChannel;
}
if (Array.Exists(TestObjects, to => !AddCalculatedChannelInputChannels(to, channels)))
{
return null;
}
if (AddedGroups.Where(to => to.Hardware.Any()).Any(to => !AddCalculatedChannelInputChannels(to, channels)))
{
return null;
}
channels.Sort();
return channels.ToArray();
}
}
private bool AddCalculatedChannelInputChannels(TestTestObject to, List<TestObjectChannel> channels)
{
var isoTestObject = to.GetISOTestObject();
if (null == isoTestObject)
{
return false;
}
foreach (var channel in isoTestObject.AllChannels)
{
if (!channel.Required || channel.Disabled) { continue; }
if (string.IsNullOrWhiteSpace(channel.SensorSerialNumber)) { continue; }
var sd = SensorsCollection.SensorsList.GetSensorBySerialNumber(channel.SensorSerialNumber);
if (null == sd || !sd.IsDigitalOutput())
{
if ((sd != null) && (sd.Bridge == SensorConstants.BridgeType.SQUIB))
{
//Put squib channels (Current and/or Voltage) in the
//Available list if and only if they are not in the graph
if (!ContainsCurrentChannel(channel))
{
var currentChannel = new TestObjectChannel(channel, isoTestObject, new TestObjectTemplate().ToISOTestObjectTemplate())
{
SquibChannelType = TestObjectChannel.SquibChannelTypes.Current,
NameOfTheChannel = channel.Name + " " + StringResources.Graph_SquibCurrent
};
channels.Add(currentChannel);
}
if (!ContainsVoltageChannel(channel))
{
channel.SquibChannelType = TestObjectChannel.SquibChannelTypes.Voltage;
channel.NameOfTheChannel = channel.Name + " " + StringResources.Graph_SquibVoltage;
channels.Add(channel);
}
}
else
{
if (ContainsCalculatedChannelInputChannel(channel)) { continue; }
channels.Add(channel);
}
}
}
return true;
}
private bool ContainsChannel(TestObjectChannel channel)
{
return _lookup.ContainsKey(channel.GetGraphId());
}
private bool ContainsCurrentChannel(TestObjectChannel channel)
{
if (channel.SquibChannelType == TestObjectChannel.SquibChannelTypes.Current)
{
return ContainsChannel(channel);
}
else
{
return _lookup.ContainsKey(channel.GetGraphId() + Constants.CURRENT_SUFFIX);
}
}
private bool ContainsVoltageChannel(TestObjectChannel channel)
{
return ContainsChannel(channel);
}
private bool ContainsCalculatedChannelInputChannel(TestObjectChannel channel)
{
return _lookup.ContainsKey(channel.GetGraphId());
}
private void ProcessLevelTriggers(System.Xml.XmlElement node, IReadOnlyDictionary<long, IGroupChannel> channelLookup)
{
var sGreaterThanEnabled = node.GetAttribute(LT_GREATERTHANENABLED);
var sGreaterThanEU = node.GetAttribute(LT_GREATERTHANTHRESHOLDEU);
var sHardwareChannelId = node.GetAttribute(LT_HARDWARECHANNELID);
var sLessThanEnabled = node.GetAttribute(LT_LESSTHANENABLED);
var sLessThanEU = node.GetAttribute(LT_LESSTHANTHRESHOLDEU);
var sensorSerialNumber = node.GetAttribute(LT_SENSORSERIALNUMBER);
var groupChannelId = node.GetAttribute(LT_GROUPCHANNELID);
var insideLowerLevelEU = 0D;
var insideUpperLevelEU = 0D;
var outsideLowerLevelEU = 0D;
var outsideUpperLevelEU = 0D;
var triggerOutsideBounds = false;
var triggerInsideBounds = false;
try
{
//these attributes were all added at the same time (later), so if one exists they all should exist, but it's possible none of them exist
var sInsideLowerLevelEU = node.GetAttribute(LT_INSIDELOWEREU);
var sInsideUpperLevelEU = node.GetAttribute(LT_INSIDEUPPEREU);
var sOutsideLowerLevelEU = node.GetAttribute(LT_OUTSIDELOWEREU);
var sOutsideUpperLevelEU = node.GetAttribute(LT_OUTSIDEUPPEREU);
var sTriggerInsideBounds = node.GetAttribute(LT_TRIGGERINSIDE);
var sTriggerOutsideBounds = node.GetAttribute(LT_TRIGGEROUTSIDE);
double.TryParse(sInsideUpperLevelEU, NumberStyles.Any, CultureInfo.InvariantCulture, out insideUpperLevelEU);
double.TryParse(sInsideLowerLevelEU, NumberStyles.Any, CultureInfo.InvariantCulture, out insideLowerLevelEU);
double.TryParse(sOutsideLowerLevelEU, NumberStyles.Any, CultureInfo.InvariantCulture, out outsideLowerLevelEU);
double.TryParse(sOutsideUpperLevelEU, NumberStyles.Any, CultureInfo.InvariantCulture, out outsideUpperLevelEU);
bool.TryParse(sTriggerInsideBounds, out triggerInsideBounds);
bool.TryParse(sTriggerOutsideBounds, out triggerOutsideBounds);
}
catch (Exception ex) { APILogger.Log(ex); }
if (bool.TryParse(sGreaterThanEnabled, out var bGreaterThanEnabled) && bool.TryParse(sLessThanEnabled, out var bLessThanEnabled)
&& double.TryParse(sGreaterThanEU, NumberStyles.Any, CultureInfo.InvariantCulture, out var greaterThanValue)
&& double.TryParse(sLessThanEU, NumberStyles.Any, CultureInfo.InvariantCulture, out var lessThanValue))
{
try
{
var lt = new LevelTriggerChannel(
groupChannelId,
sHardwareChannelId,
sensorSerialNumber,
bGreaterThanEnabled,
greaterThanValue,
bLessThanEnabled,
lessThanValue,
insideLowerLevelEU,
insideUpperLevelEU,
outsideLowerLevelEU,
outsideUpperLevelEU,
triggerOutsideBounds,
triggerInsideBounds);
//Assign GroupChannel so that we get the database ID of the Channel
if (long.TryParse(groupChannelId, out var l))
{
if (channelLookup.ContainsKey(l))
{
lt.GroupChannel = channelLookup[l];
}
}
SetLevelTrigger(lt);
}
catch (Exception ex) { APILogger.Log(ex); }
}
}
private void ProcessLevelTriggersPre20(System.Xml.XmlElement node)
{
var sGreaterThanEnabled = node.GetAttribute(LT_GREATERTHANENABLED);
var sGreaterThanEU = node.GetAttribute(LT_GREATERTHANTHRESHOLDEU);
var sHardwareChannelId = node.GetAttribute(LT_HARDWARECHANNELID);
var sLessThanEnabled = node.GetAttribute(LT_LESSTHANENABLED);
var sLessThanEU = node.GetAttribute(LT_LESSTHANTHRESHOLDEU);
var sensorSerialNumber = node.GetAttribute(LT_SENSORSERIALNUMBER);
var groupChannelId = node.GetAttribute(LT_TESTOBJECTCHANNELID);
var insideLowerLevelEU = 0D;
var insideUpperLevelEU = 0D;
var outsideLowerLevelEU = 0D;
var outsideUpperLevelEU = 0D;
var triggerOutsideBounds = false;
var triggerInsideBounds = false;
try
{
//these attributes were all added at the same time (later), so if one exists they all should exist, but it's possible none of them exist
var sInsideLowerLevelEU = node.GetAttribute(LT_INSIDELOWEREU);
var sInsideUpperLevelEU = node.GetAttribute(LT_INSIDEUPPEREU);
var sOutsideLowerLevelEU = node.GetAttribute(LT_OUTSIDELOWEREU);
var sOutsideUpperLevelEU = node.GetAttribute(LT_OUTSIDEUPPEREU);
var sTriggerInsideBounds = node.GetAttribute(LT_TRIGGERINSIDE);
var sTriggerOutsideBounds = node.GetAttribute(LT_TRIGGEROUTSIDE);
double.TryParse(sInsideUpperLevelEU, NumberStyles.Any, CultureInfo.InvariantCulture, out insideUpperLevelEU);
double.TryParse(sInsideLowerLevelEU, NumberStyles.Any, CultureInfo.InvariantCulture, out insideLowerLevelEU);
double.TryParse(sOutsideLowerLevelEU, NumberStyles.Any, CultureInfo.InvariantCulture, out outsideLowerLevelEU);
double.TryParse(sOutsideUpperLevelEU, NumberStyles.Any, CultureInfo.InvariantCulture, out outsideUpperLevelEU);
bool.TryParse(sTriggerInsideBounds, out triggerInsideBounds);
bool.TryParse(sTriggerOutsideBounds, out triggerOutsideBounds);
}
catch (Exception ex) { APILogger.Log(ex); }
if (bool.TryParse(sGreaterThanEnabled, out var bGreaterThanEnabled) && bool.TryParse(sLessThanEnabled, out var bLessThanEnabled)
&& double.TryParse(sGreaterThanEU, NumberStyles.Any, CultureInfo.InvariantCulture, out var greaterThanValue)
&& double.TryParse(sLessThanEU, NumberStyles.Any, CultureInfo.InvariantCulture, out var lessThanValue))
{
try
{
var hardwareChannelIdToGroupChannelIdMap = new Dictionary<string, long>();
foreach (var group in Groups)
{
var channels = ChannelsForGroup[group];
foreach (var groupChannel in channels)
{
hardwareChannelIdToGroupChannelIdMap[groupChannel.HardwareId] = groupChannel.Id;
}
}
var lt = new LevelTriggerChannel(
groupChannelId,
sHardwareChannelId,
sensorSerialNumber,
bGreaterThanEnabled,
greaterThanValue,
bLessThanEnabled,
lessThanValue,
insideLowerLevelEU,
insideUpperLevelEU,
outsideLowerLevelEU,
outsideUpperLevelEU,
triggerOutsideBounds,
triggerInsideBounds);
SetLevelTrigger(lt);
}
catch (Exception ex) { APILogger.Log(ex); }
}
}
/// <summary>
/// Processes Added Groups from a Test Setup node in xml
/// </summary>
/// <param name="root"></param>
/// <param name="testObjectLookup"></param>
/// <param name="sensorLookup"></param>
private void ProcessAddedGroupsPre20(System.Xml.XmlElement root, IDictionary<string, TestObject> testObjectLookup, Dictionary<string, SensorData> sensorLookup)
{
var values = new Dictionary<DbOperations.TestSetups.TestSetupObjectFields, string>();
var sensorsToBeSet = new List<Tuple<string, string, SensorData>>();
foreach (var child in root.ChildNodes)
{
if (!(child is System.Xml.XmlElement node)) { continue; }
if (Enum.TryParse(node.Name, out DbOperations.TestSetups.TestSetupObjectFields field))
{
values[field] = node.InnerText.Trim();
}
else if (node.Name == CHANNELSETTINGS_ROOT)
{
ProcessChannelSetting(node, sensorLookup, ref sensorsToBeSet);
}
else { System.Diagnostics.Trace.WriteLine(node.Name); }
}
if (values.ContainsKey(DbOperations.TestSetups.TestSetupObjectFields.TestObjectSerialNumber) ||
values.ContainsKey(DbOperations.TestSetups.TestSetupObjectFields.TestObjectName))
{
var serial = values.ContainsKey(DbOperations.TestSetups.TestSetupObjectFields.TestObjectSerialNumber) ?
values[DbOperations.TestSetups.TestSetupObjectFields.TestObjectSerialNumber] :
values[DbOperations.TestSetups.TestSetupObjectFields.TestObjectName];
var group = testObjectLookup[serial];
int displayOrder = -1;
if (values.ContainsKey(DbOperations.TestSetups.TestSetupObjectFields.DisplayOrder))
{
var o = values[DbOperations.TestSetups.TestSetupObjectFields.DisplayOrder];
if (!DBNull.Value.Equals(o))
{
displayOrder = Convert.ToInt32(o);
}
}
AddAddedGroup(group, values[DbOperations.TestSetups.TestSetupObjectFields.TestObjectType],
values[DbOperations.TestSetups.TestSetupObjectFields.TestObjectPosition],
values[DbOperations.TestSetups.TestSetupObjectFields.TestSetupName], displayOrder);
//}
}
else
{
APILogger.Log("TestTemplate::ProcessAddedGroups value not found [test object serial number]");
throw new NotSupportedException("TestTemplate::ProcessAddedGroups value not found [test object serial number]");
}
if (sensorsToBeSet.Any())
{
using (var eSensors = sensorsToBeSet.GetEnumerator())
{
while (eSensors.MoveNext())
{
SetSensor(eSensors.Current.Item3, eSensors.Current.Item1, eSensors.Current.Item2);
}
}
}
}
/// <summary>
/// processes a group from a test setup node in xml
/// </summary>
/// <param name="root"></param>
/// <param name="testObjectLookup"></param>
/// <param name="sensorLookup"></param>
private void ProcessTestObjectNode(System.Xml.XmlElement root, IDictionary<string, TestObject> testObjectLookup, Dictionary<string, SensorData> sensorLookup)
{
var values = new Dictionary<DbOperations.TestSetups.TestSetupObjectFields, string>();
List<Tuple<string, string, SensorData>> sensorsToBeSet = new List<Tuple<string, string, SensorData>>();
foreach (var child in root.ChildNodes)
{
if (!(child is System.Xml.XmlElement node)) { continue; }
if (Enum.TryParse(node.Name, out DbOperations.TestSetups.TestSetupObjectFields field))
{
values[field] = node.InnerText.Trim();
}
else
{
switch (node.Name)
{
case CHANNELSETTINGS_ROOT:
ProcessChannelSetting(node, sensorLookup, ref sensorsToBeSet);
break;
case TO_SERIALNUMBER:
//Handle the backward-compatibility of the switch from <TestObjectSerialNumber> to <TestObjectName>
values[DbOperations.TestSetups.TestSetupObjectFields.TestObjectName] = node.InnerText;
break;
}
}
}
var excitationWarmupMs = Convert.ToInt32(values[DbOperations.TestSetups.TestSetupObjectFields.ExcitationWarmupTimeMS], CultureInfo.InvariantCulture);
var targetSampleRate = Convert.ToDouble(values[DbOperations.TestSetups.TestSetupObjectFields.TargetSampleRate], CultureInfo.InvariantCulture);
var key = values.ContainsKey(DbOperations.TestSetups.TestSetupObjectFields.TestObjectSerialNumber)
? DbOperations.TestSetups.TestSetupObjectFields.TestObjectSerialNumber
: DbOperations.TestSetups.TestSetupObjectFields.TestObjectName;
var groupkey = values[key];
if (testObjectLookup.ContainsKey(groupkey))
{
var to = testObjectLookup[groupkey];
var displayOrder = -1;
if (values.ContainsKey(DbOperations.TestSetups.TestSetupObjectFields.DisplayOrder))
{
var value = values[DbOperations.TestSetups.TestSetupObjectFields.DisplayOrder];
if (!DBNull.Value.Equals(value))
{
displayOrder = Convert.ToInt32(value);
}
}
AddTestObject(
to,
excitationWarmupMs, targetSampleRate,
values[DbOperations.TestSetups.TestSetupObjectFields.TestObjectType],
values[DbOperations.TestSetups.TestSetupObjectFields.TestObjectPosition],
displayOrder);
}
if (sensorsToBeSet.Any())
{
using (var eSensors = sensorsToBeSet.GetEnumerator())
{
while (eSensors.MoveNext())
{
SetSensor(eSensors.Current.Item3, eSensors.Current.Item1, eSensors.Current.Item2);
}
}
}
}
/// <summary>
/// processes a DASHardware from a TestSetup node in xml
/// </summary>
/// <param name="root"></param>
private void ProcessDASHardwareNode(System.Xml.XmlElement root)
{
var values = new Dictionary<DbOperations.TestSetups.TestSetupDASHardwareFields, string>();
foreach (var child in root.ChildNodes)
{
if (!(child is System.Xml.XmlElement node)) { continue; }
if (Enum.TryParse(node.Name, out DbOperations.TestSetups.TestSetupDASHardwareFields field))
{
values[field] = node.InnerText;
}
}
DASSampleRateList[values[DbOperations.TestSetups.TestSetupDASHardwareFields.SerialNumber]] =
Convert.ToDouble(values[DbOperations.TestSetups.TestSetupDASHardwareFields.SamplesPerSecond]);
//FB15759: if an older file without AAF, mark freq 0 and we'll fix later
DASAAFRateList[values[DbOperations.TestSetups.TestSetupDASHardwareFields.SerialNumber]] = values.ContainsKey(DbOperations.TestSetups.TestSetupDASHardwareFields.AntiAliasFilterRate)
? Convert.ToSingle(values[DbOperations.TestSetups.TestSetupDASHardwareFields.AntiAliasFilterRate])
: 0;
DASClockMasterList[values[DbOperations.TestSetups.TestSetupDASHardwareFields.SerialNumber]] =
values.ContainsKey(DbOperations.TestSetups.TestSetupDASHardwareFields.IsClockMaster) &&
Convert.ToBoolean(values[DbOperations.TestSetups.TestSetupDASHardwareFields.IsClockMaster]);
DASPTPDomainIDList[values[DbOperations.TestSetups.TestSetupDASHardwareFields.SerialNumber]] = values.ContainsKey(DbOperations.TestSetups.TestSetupDASHardwareFields.PTPDomainID)
? Convert.ToByte(values[DbOperations.TestSetups.TestSetupDASHardwareFields.PTPDomainID])
: (byte)0;
}
private static IGroupListViewModel _vm = null;
public IGroup CreateGroup(IGroupDbRecord groupRecord, List<string> includedHardwareStringList, List<int> dasIdList)
{
if (null == _vm)
{
var unityContainer = ContainerLocator.Container.Resolve<IUnityContainer>();
_vm = unityContainer.Resolve<IGroupListViewModel>();
}
return _vm.CreateGroup(groupRecord, includedHardwareStringList, dasIdList);
}
public IGroup CreateGroup(List<string> includedHardwareStringList)
{
if (null == _vm)
{
var unityContainer = ContainerLocator.Container.Resolve<IUnityContainer>();
_vm = unityContainer.Resolve<IGroupListViewModel>();
}
return _vm.CreateGroup(includedHardwareStringList);
}
/// <summary>
/// processes a Group from a TestSetup node in xml
/// </summary>
/// <param name="root"></param>
/// <param name="testObjectLookup"></param>
/// <param name="sensorLookup"></param>
private void ProcessGroupNode(System.Xml.XmlElement root, IDictionary<string, IGroup> groupLookup,
Dictionary<string, SensorData> sensorLookup, IChannelSetting[] channelDefaults, List<SensorCalibration> sensorCalibrations)
{
var values = new Dictionary<DbOperations.TestSetups.TestSetupGroupFields, string>();
var includedHardwareStringList = new List<string>();
var channelLookup = new Dictionary<long, IGroupChannel>();
foreach (var child in root.ChildNodes)
{
if (!(child is System.Xml.XmlElement node)) { continue; }
if (Enum.TryParse(node.Name, out DbOperations.TestSetups.TestSetupGroupFields field))
{
values[field] = node.InnerText;
}
else
{
switch (node.Name)
{
case HARDWARE_LIST:
includedHardwareStringList = ProcessHardwareXMLElement(node);
break;
case CHANNEL_ROOT:
var channel = ProcessChannelNode(node, values[DbOperations.TestSetups.TestSetupGroupFields.DisplayName], groupLookup, channelDefaults, sensorLookup,
sensorCalibrations);
channelLookup[channel.Id] = channel;
break;
}
}
}
IGroup group = null;
var groupkey = "";
if (Application.Current.Dispatcher.CheckAccess())
{
var key = DbOperations.TestSetups.TestSetupGroupFields.Name;
groupkey = values[key];
group = CreateGroup(includedHardwareStringList);
}
else
{
ManualResetEvent resetEvent = new ManualResetEvent(false);
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
var key = DbOperations.TestSetups.TestSetupGroupFields.Name;
groupkey = values[key];
group = CreateGroup(includedHardwareStringList);
resetEvent.Set();
}));
resetEvent.WaitOne();
}
group.Name = groupkey;
group.Embedded = true;
group.DisplayName = values[DbOperations.TestSetups.TestSetupGroupFields.DisplayName];
group.Description = values[DbOperations.TestSetups.TestSetupGroupFields.Description];
group.DisplayOrder = Convert.ToInt32(values[DbOperations.TestSetups.TestSetupGroupFields.DisplayOrder]);
group.Position = values[DbOperations.TestSetups.TestSetupGroupFields.Position];
group.TestObject = values[DbOperations.TestSetups.TestSetupGroupFields.TestObjectType];
if (values.ContainsKey(DbOperations.TestSetups.TestSetupGroupFields.Id))
{
group.Id = Convert.ToInt32(values[DbOperations.TestSetups.TestSetupGroupFields.Id]);
}
if (values.ContainsKey(DbOperations.TestSetups.TestSetupGroupFields.StaticGroupId))
{
//Must be a 2.1 or later export
if (string.IsNullOrWhiteSpace(values[DbOperations.TestSetups.TestSetupGroupFields.StaticGroupId]) ||
!groupLookup.ContainsKey(values[DbOperations.TestSetups.TestSetupGroupFields.DisplayName]))
{
group.StaticGroupId = null;
}
else
{
group.StaticGroupId = Convert.ToInt32(values[DbOperations.TestSetups.TestSetupGroupFields.StaticGroupId]);
}
}
var sensors = sensorLookup.Values.ToArray();
AddGroup(group, channelLookup, sensors);
}
/// <summary>
/// processes a channel setting for a test setup from a test setup node in xml
/// </summary>
/// <param name="root"></param>
/// <param name="lookup"></param>
private void ProcessChannelSetting(System.Xml.XmlElement root, Dictionary<string, SensorData> lookup, ref List<Tuple<string, string, SensorData>> sensors)
{
var chid = "";
var sensorserial = "";
var setting = "";
var objname = "";
var disabled = false;
foreach (var node in root.ChildNodes)
{
if (node is System.Xml.XmlElement)
{
var child = node as System.Xml.XmlElement;
if (!Enum.TryParse(child.Name, out DbOperations.TestSetups.ChannelSettingFields field)) continue;
switch (field)
{
case DbOperations.TestSetups.ChannelSettingFields.ChannelId: chid = child.InnerText; break;
case DbOperations.TestSetups.ChannelSettingFields.SensorSerial: sensorserial = child.InnerText; break;
case DbOperations.TestSetups.ChannelSettingFields.Setting: setting = child.InnerText; break;
case DbOperations.TestSetups.ChannelSettingFields.TestName: break;
case DbOperations.TestSetups.ChannelSettingFields.TestObjectName: objname = child.InnerText.Trim(); break;
case DbOperations.TestSetups.ChannelSettingFields.Disabled:
disabled = Convert.ToBoolean(child.InnerText,
CultureInfo.InvariantCulture);
break;
}
}
}
SetDisabled(objname, chid, disabled);
var sd = TestTemplateList.GetSensorFromSettings(setting, sensorserial, lookup);
if (null == sd) { return; }
//SetSensor(sd, objname, chid);
sensors.Add(new Tuple<string, string, SensorData>(objname, chid, sd));
}
/// <summary>
/// processes a channel setting for a test setup from a test setup node in xml
/// </summary>
/// <param name="root"></param>
/// <param name="lookup"></param>
private List<string> ProcessHardwareXMLElement(System.Xml.XmlElement root)
{
var includedHardwareStringList = new List<string>();
foreach (var child in root.ChildNodes)
{
if (!(child is System.Xml.XmlElement node)) { continue; }
if (Enum.TryParse(node.Name, out DbOperations.TestSetups.GroupsGroupHardwareListFields field))
{
switch (field)
{
case DbOperations.TestSetups.GroupsGroupHardwareListFields.Hardware:
includedHardwareStringList.Add(node.InnerText);
break;
}
}
}
return includedHardwareStringList;
}
private IGroupChannel ProcessChannelNode(System.Xml.XmlElement root, string groupDisplayName, IDictionary<string, IGroup> groupLookup, IChannelSetting[] channelDefaults,
Dictionary<string, SensorData> sensorLookup, List<SensorCalibration> sensorCalibrations)
{
var channel = new GroupChannel(true, groupDisplayName, null, channelDefaults);
foreach (var child in root.ChildNodes)
{
if (!(child is System.Xml.XmlElement node)) { continue; }
if (Enum.TryParse(node.Name, out DbOperations.TestSetups.ChannelFields field))
{
switch (field)
{
case DbOperations.TestSetups.ChannelFields.ISOChannelName: channel.IsoChannelName = node.InnerText; break;
case DbOperations.TestSetups.ChannelFields.ISOCode: channel.IsoCode = node.InnerText; break;
case DbOperations.TestSetups.ChannelFields.UserChannelName: channel.UserChannelName = node.InnerText; break;
case DbOperations.TestSetups.ChannelFields.UserCode: channel.UserCode = node.InnerText; break;
case DbOperations.TestSetups.ChannelFields.SensorId:
channel.SensorId = Convert.ToInt32(node.InnerText, CultureInfo.InvariantCulture);
break;
case DbOperations.TestSetups.ChannelFields.DASId:
channel.DASId = Convert.ToInt32(node.InnerText,
CultureInfo.InvariantCulture);
break;
case DbOperations.TestSetups.ChannelFields.DASChannelIdx:
channel.DASChannelIndex = Convert.ToInt32(node.InnerText,
CultureInfo.InvariantCulture);
break;
case DbOperations.TestSetups.ChannelFields.TestSetupOrder:
channel.TestSetupOrder = Convert.ToInt32(node.InnerText,
CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.ChannelFields.GroupOrder:
channel.GroupChannelOrder = Convert.ToInt32(node.InnerText,
CultureInfo.InvariantCulture);
break;
case DbOperations.TestSetups.ChannelFields.Disabled: channel.IsDisabled = Convert.ToBoolean(node.InnerText, CultureInfo.InvariantCulture); break;
case DbOperations.TestSetups.ChannelFields.Settings: ProcessSettingsNode(node, channel, groupLookup, sensorLookup, sensorCalibrations); break;
case DbOperations.TestSetups.ChannelFields.Id:
channel.Id = Convert.ToInt32(node.InnerText,
CultureInfo.InvariantCulture); break;
}
}
}
return channel;
}
/// <summary>
/// processes a channel setting for a test setup from a test setup node in xml
/// </summary>
/// <param name="root"></param>
/// <param name="channel"></param>
/// <param name="groupLookup"></param>
private void ProcessSettingsNode(System.Xml.XmlElement root, GroupChannel channel, IDictionary<string, IGroup> groupLookup, Dictionary<string, SensorData> sensorLookup,
List<SensorCalibration> sensorCalibrations)
{
var range = "";
//var cfc = "";
var filterClass = "";
var polarity = "";
var acCouplingEnabled = "";
var bridgeType = "";
var duration = "";
var delay = "";
var limitDuration = "";
var outputMode = "";
var digitalOutDuration = "";
var digitalOutDelay = "";
var digitalOutLimitDuration = "";
var sqMode = "";
var squibDuration = "";
var squibDelay = "";
var squibCurrent = "";
var squibLimitDuration = "";
var diMode = "";
var defaultValue = "";
var activeValue = "";
var uartBaudRate = "";
var uartDataBits = "";
var uartStopBits = "";
var uartParity = "";
var uartFlowControl = "";
var uartDataFormat = "";
var streamOutUDPProfile = "";
var streamOutUDPAddress = "";
var streamOutUDPTimeChannelId = "";
var streamOutUDPDataChannelId = "";
var streamOutUDPTmNSConfig = "";
var streamOutIRIGTimeDataPacketIntervalMs = "";
var streamOutTMATIntervalMs = "";
var streamInUDPAddress = "";
//15270 Sensor Import does not import most channel settings
string userValue1, userValue2, userValue3, zeroMethod, zeroStart, zeroEnd, initialOffset;
userValue1 = userValue2 = userValue3 = zeroMethod = zeroStart = zeroEnd = initialOffset = string.Empty;
if (root.ChildNodes.Count > 0)
{
foreach (var node in root.ChildNodes)
{
if (node is System.Xml.XmlElement)
{
var child = node as System.Xml.XmlElement;
if (Enum.TryParse(child.Name, out DbOperations.TestSetups.SettingsFields field))
{
switch (field)
{
case DbOperations.TestSetups.SettingsFields.Range:
range = string.IsNullOrWhiteSpace(child.InnerText) ? GetGroupRange(channel, groupLookup) : child.InnerText;
break;
case DbOperations.TestSetups.SettingsFields.CFC:
//FB 13120 Convert pre version 5 xml to 6
var fc = FilterClass.GetFilterClassFromIsoCode(child.InnerText);
filterClass = $"{fc.FClass},{fc.Frequency}";
break;
case DbOperations.TestSetups.SettingsFields.FilterClass:
filterClass = child.InnerText;
break;
case DbOperations.TestSetups.SettingsFields.Polarity: polarity = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.LimitDuration: limitDuration = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.Duration: duration = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.Delay: delay = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.OutputMode: outputMode = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.DigitalOutDelay: digitalOutDelay = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.DigitalOutDuration: digitalOutDuration = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.DigitalOutLimitDuration: digitalOutLimitDuration = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.SQMode: sqMode = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.SquibDelay: squibDelay = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.SquibCurrent: squibCurrent = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.SquibDuration: squibDuration = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.SquibLimitDuration: squibLimitDuration = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.DIMode: diMode = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.DefaultValue: defaultValue = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.ActiveValue: activeValue = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.UserValue1: userValue1 = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.UserValue2: userValue2 = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.UserValue3: userValue3 = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.ZeroMethod: zeroMethod = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.ZeroMethodStart: zeroStart = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.ZeroMethodEnd: zeroEnd = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.InitialOffset: initialOffset = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.UartBaudRate: uartBaudRate = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.UartDataBits: uartDataBits = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.UartStopBits: uartStopBits = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.UartParity: uartParity = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.UartFlowControl: uartFlowControl = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.UartDataFormat: uartDataFormat = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.StreamOutUDPProfile: streamOutUDPProfile = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.StreamOutUDPAddress: streamOutUDPAddress = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.StreamOutUDPTimeChannelId: streamOutUDPTimeChannelId = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.StreamOutUDPDataChannelId: streamOutUDPDataChannelId = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.StreamOutUDPTmNSConfig: streamOutUDPTmNSConfig = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.StreamOutIRIGTimeDataPacketIntervalMs: streamOutIRIGTimeDataPacketIntervalMs = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.StreamOutTMATSIntervalMs: streamOutTMATIntervalMs = child.InnerText; break;
case DbOperations.TestSetups.SettingsFields.ACCouplingEnabled: acCouplingEnabled = child.InnerText; break;
//33415 Voltage insertion channel should be half bridge
case DbOperations.TestSetups.SettingsFields.BridgeType: bridgeType = child.InnerText; break;
}
}
}
}
}
else
{
//Settings is empty, so get Range from Group
range = GetGroupRange(channel, groupLookup);
//18771 Get channel settings from sensors if <Settings> is empty
filterClass = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.FilterClass);
polarity = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.Polarity);
limitDuration = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.LimitDuration);
duration = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.Duration);
delay = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.Delay);
outputMode = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.OutputMode);
digitalOutDelay = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.DigitalOutDelay);
digitalOutDuration = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.DigitalOutDuration);
digitalOutLimitDuration = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.DigitalOutLimitDuration);
sqMode = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.SQMode);
squibDelay = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.SquibDelay);
squibCurrent = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.SquibCurrent);
squibDuration = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.SquibDuration);
squibLimitDuration = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.SquibLimitDuration);
diMode = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.DIMode);
defaultValue = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.DefaultValue);
activeValue = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.ActiveValue);
userValue1 = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.UserValue1);
userValue2 = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.UserValue2);
userValue3 = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.UserValue3);
//18363 add uart sensors
uartBaudRate = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.UartBaudRate);
uartDataBits = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.UartDataBits);
uartStopBits = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.UartStopBits);
uartParity = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.UartParity);
uartFlowControl = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.UartFlowControl);
uartDataFormat = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.UartDataFormat);
//18362 add stream setting sensors
streamOutUDPProfile = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.StreamOutUDPProfile);
streamOutUDPAddress = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.StreamOutUDPAddress);
streamOutUDPTimeChannelId = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.StreamOutUDPTimeChannelId);
streamOutUDPDataChannelId = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.StreamOutUDPDataChannelId);
streamOutUDPTmNSConfig = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.StreamOutUDPTmNSConfig);
streamOutIRIGTimeDataPacketIntervalMs = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.StreamOutIRIGTimeDataPacketIntervalMs);
streamOutTMATIntervalMs = GetSettingFromSensorLookup(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.StreamOutTMATSIntervalMs);
//18771 Get these channel settings from the sensor calibration
zeroMethod = GetSettingFromCalibration(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.ZeroMethod, sensorCalibrations);
zeroStart = GetSettingFromCalibration(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.ZeroMethodStart, sensorCalibrations);
zeroEnd = GetSettingFromCalibration(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.ZeroMethodEnd, sensorCalibrations);
initialOffset = GetSettingFromCalibration(sensorLookup, channel, DbOperations.TestSetups.SettingsFields.InitialOffset, sensorCalibrations);
}
//Range,CFC,Polarity
var settings = new List<IChannelSetting>();
var dictionary = DbOperations.GetSettingsLookup();
if (!string.IsNullOrWhiteSpace(range))
{
var rangeTuple = dictionary[ChannelSettingBase.RANGE];
settings.Add(new ChannelSettingBase(rangeTuple.Item1, rangeTuple.Item2, rangeTuple.Item3)
{ DoubleValue = Convert.ToDouble(range, CultureInfo.InvariantCulture) });
}
if (!string.IsNullOrWhiteSpace(acCouplingEnabled))
{
var acCouplingTuple = dictionary[ChannelSettingBase.ACCouplingEnabled];
var setting = new ChannelSettingBase(acCouplingTuple.Item1, acCouplingTuple.Item2, acCouplingTuple.Item3);
if (bool.TryParse(acCouplingEnabled, out var b))
{
setting.BoolValue = b;
}
settings.Add(setting);
}
//FB 13120 filter class will be used instead of cfc
if (!string.IsNullOrWhiteSpace(filterClass))
{
var FilterClassTuple = dictionary[ChannelSettingBase.FilterClass];
settings.Add(new ChannelSettingBase(FilterClassTuple.Item1, FilterClassTuple.Item2, FilterClassTuple.Item3) { Value = filterClass });
}
if (!string.IsNullOrWhiteSpace(polarity))
{
var polarityTuple = dictionary[ChannelSettingBase.POLARITY];
settings.Add(new ChannelSettingBase(polarityTuple.Item1, polarityTuple.Item2, polarityTuple.Item3)
{ Value = polarity });
}
//33415 Voltage insertion channel should be half bridge
if (!string.IsNullOrWhiteSpace(bridgeType))
{
var bridgeTypeTuple = dictionary[ChannelSettingBase.BRIDGE_TYPE];
settings.Add(new ChannelSettingBase(bridgeTypeTuple.Item1, bridgeTypeTuple.Item2, bridgeTypeTuple.Item3) { Value = bridgeType });
}
if (!string.IsNullOrWhiteSpace(limitDuration))
{
var tuple = dictionary[ChannelSettingBase.DIGITALOUT_LIMIT_DURATION];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ BoolValue = Convert.ToBoolean(limitDuration) });
tuple = dictionary[ChannelSettingBase.SQUIB_LIMIT_DURATION];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ BoolValue = Convert.ToBoolean(limitDuration) });
}
if (!string.IsNullOrWhiteSpace(duration))
{
var tuple = dictionary[ChannelSettingBase.DIGITALOUT_DURATION];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ DoubleValue = Convert.ToDouble(duration, CultureInfo.InvariantCulture) });
tuple = dictionary[ChannelSettingBase.SQUIB_DURATION];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ DoubleValue = Convert.ToDouble(duration, CultureInfo.InvariantCulture) });
}
if (!string.IsNullOrWhiteSpace(delay))
{
var tuple = dictionary[ChannelSettingBase.DIGITALOUT_DELAY];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ DoubleValue = Convert.ToDouble(delay, CultureInfo.InvariantCulture) });
tuple = dictionary[ChannelSettingBase.SQUIB_DELAY];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ DoubleValue = Convert.ToDouble(delay, CultureInfo.InvariantCulture) });
}
if (!string.IsNullOrWhiteSpace(outputMode))
{
var tuple = dictionary[ChannelSettingBase.OUTPUT_MODE];
if (!int.TryParse(outputMode, out int iTemp))
{
APILogger.Log("invalid output mode: outputMode for channel", channel.GetChannelName(SerializedSettings.ISOViewMode));
}
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ IntValue = iTemp });
}
if (!string.IsNullOrWhiteSpace(digitalOutDelay))
{
var tuple = dictionary[ChannelSettingBase.DIGITALOUT_DELAY];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ DoubleValue = Convert.ToDouble(digitalOutDelay, CultureInfo.InvariantCulture) });
}
if (!string.IsNullOrWhiteSpace(digitalOutDuration))
{
var tuple = dictionary[ChannelSettingBase.DIGITALOUT_DURATION];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ DoubleValue = Convert.ToDouble(digitalOutDuration, CultureInfo.InvariantCulture) });
}
if (!string.IsNullOrWhiteSpace(digitalOutLimitDuration))
{
var tuple = dictionary[ChannelSettingBase.DIGITALOUT_LIMIT_DURATION];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ BoolValue = Convert.ToBoolean(digitalOutLimitDuration) });
}
if (!string.IsNullOrWhiteSpace(sqMode))
{
var tuple = dictionary[ChannelSettingBase.SQMODE];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ IntValue = Convert.ToInt32(sqMode) });
}
if (!string.IsNullOrWhiteSpace(squibDelay))
{
var tuple = dictionary[ChannelSettingBase.SQUIB_DELAY];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ DoubleValue = Convert.ToDouble(squibDelay, CultureInfo.InvariantCulture) });
}
if (!string.IsNullOrWhiteSpace(squibCurrent))
{
var tuple = dictionary[ChannelSettingBase.SQUIB_CURRENT];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ DoubleValue = Convert.ToDouble(squibCurrent, CultureInfo.InvariantCulture) });
}
if (!string.IsNullOrWhiteSpace(squibDuration))
{
var tuple = dictionary[ChannelSettingBase.SQUIB_DURATION];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ DoubleValue = Convert.ToDouble(squibDuration, CultureInfo.InvariantCulture) });
}
if (!string.IsNullOrWhiteSpace(squibLimitDuration))
{
var tuple = dictionary[ChannelSettingBase.SQUIB_LIMIT_DURATION];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ BoolValue = Convert.ToBoolean(squibLimitDuration) });
}
if (!string.IsNullOrWhiteSpace(uartBaudRate))
{
var tuple = dictionary[ChannelSettingBase.BAUD_RATE];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ IntValue = Convert.ToInt32(uartBaudRate) });
}
if (!string.IsNullOrWhiteSpace(uartDataBits))
{
var tuple = dictionary[ChannelSettingBase.DATA_BITS];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ IntValue = Convert.ToInt32(uartDataBits) });
}
if (!string.IsNullOrWhiteSpace(uartStopBits))
{
var tuple = dictionary[ChannelSettingBase.STOP_BITS];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ Value = uartStopBits });
}
if (!string.IsNullOrWhiteSpace(uartParity))
{
var tuple = dictionary[ChannelSettingBase.PARITY];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ Value = uartParity });
}
if (!string.IsNullOrWhiteSpace(uartFlowControl))
{
var tuple = dictionary[ChannelSettingBase.FLOW_CONTROL];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ Value = uartFlowControl });
}
if (!string.IsNullOrWhiteSpace(uartDataFormat))
{
var tuple = dictionary[ChannelSettingBase.DATA_FORMAT];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ Value = uartDataFormat });
}
if (!string.IsNullOrWhiteSpace(diMode))
{
var tuple = dictionary[ChannelSettingBase.DIMODE];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ IntValue = Convert.ToInt32(diMode) });
}
if (!string.IsNullOrWhiteSpace(defaultValue))
{
var tuple = dictionary[ChannelSettingBase.DEFAULT_VALUE];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ DoubleValue = Convert.ToDouble(defaultValue, CultureInfo.InvariantCulture) });
}
if (!string.IsNullOrWhiteSpace(activeValue))
{
var tuple = dictionary[ChannelSettingBase.ACTIVE_VALUE];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ DoubleValue = Convert.ToDouble(activeValue, CultureInfo.InvariantCulture) });
}
if (!string.IsNullOrWhiteSpace(streamInUDPAddress))
{
var tuple = dictionary[ChannelSettingBase.UDP_ADDRESS_IN];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ Value = streamInUDPAddress });
}
if (!string.IsNullOrWhiteSpace(streamOutUDPProfile))
{
var tuple = dictionary[ChannelSettingBase.UDP_PROFILE];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ Value = streamOutUDPProfile });
}
if (!string.IsNullOrWhiteSpace(streamOutUDPAddress))
{
var tuple = dictionary[ChannelSettingBase.UDP_ADDRESS];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ Value = streamOutUDPAddress });
}
if (!string.IsNullOrWhiteSpace(streamOutUDPTimeChannelId))
{
var tuple = dictionary[ChannelSettingBase.UDP_TIME_CHID];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ IntValue = Convert.ToInt32(streamOutUDPTimeChannelId) });
}
if (!string.IsNullOrWhiteSpace(streamOutUDPDataChannelId))
{
var tuple = dictionary[ChannelSettingBase.UDP_DATA_CHID];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ IntValue = Convert.ToInt32(streamOutUDPDataChannelId) });
}
if (!string.IsNullOrWhiteSpace(streamOutUDPTmNSConfig))
{
var tuple = dictionary[ChannelSettingBase.UDP_TMNS_CONFIG];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ Value = streamOutUDPTmNSConfig });
}
if (!string.IsNullOrWhiteSpace(streamOutIRIGTimeDataPacketIntervalMs))
{
var tuple = dictionary[ChannelSettingBase.IRIG_TDP_INTERVAL_MS];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ IntValue = Convert.ToInt32(streamOutIRIGTimeDataPacketIntervalMs) });
}
if (!string.IsNullOrWhiteSpace(streamOutTMATIntervalMs))
{
var tuple = dictionary[ChannelSettingBase.TMATS_INTERVAL_MS];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ IntValue = Convert.ToInt32(streamOutTMATIntervalMs) });
}
ProcessUserValues(userValue1, userValue2, userValue3, dictionary, ref settings);
var bHadZeroMethod = ProcessZeroMethod(zeroMethod, zeroStart, zeroEnd, dictionary, ref settings);
if (!string.IsNullOrWhiteSpace(initialOffset))
{
var tuple = dictionary[ChannelSettingBase.INITIAL_OFFSET];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{
Value = initialOffset
});
}
channel.ChannelSettings = settings.ToArray();
//15262 Absolute zero sensors in test setup change to ave over time after import.
//there's a FixZeroMethodSetting that will explicitly correct the zeromethod if it's not present
//in the xml, however the default setting could have been set, so unset it here
if (!bHadZeroMethod)
{
channel.RemoveZeroMethodSetting();
}
}
/// <summary>
/// This is for use when there are no elements in the <Settings> of a channel
/// </summary>
/// <param name="sensorLookup"></param>
/// <param name="channel"></param>
/// <param name="field"></param>
/// <param name="calibrations"></param>
/// <returns></returns>
private string GetSettingFromCalibration(Dictionary<string, SensorData> sensorLookup, GroupChannel channel, DbOperations.TestSetups.SettingsFields field,
List<SensorCalibration> calibrations)
{
var result = string.Empty;
var serialNumber = string.Empty;
foreach (var entry in sensorLookup)
{
if (entry.Value.Comment == channel.ChannelName)
{
serialNumber = entry.Value.SerialNumber;
break;
}
}
if (!string.IsNullOrWhiteSpace(serialNumber))
{
foreach (var calibration in calibrations)
{
if (calibration.SerialNumber == serialNumber)
{
switch (field)
{
case DbOperations.TestSetups.SettingsFields.ZeroMethod:
result = calibration.ZeroMethods.Methods.ToList().Last().Method.ToString();
break;
case DbOperations.TestSetups.SettingsFields.ZeroMethodStart:
result = calibration.ZeroMethods.Methods.ToList().Last().Start.ToString();
break;
case DbOperations.TestSetups.SettingsFields.ZeroMethodEnd:
result = calibration.ZeroMethods.Methods.ToList().Last().End.ToString();
break;
case DbOperations.TestSetups.SettingsFields.InitialOffset:
var initialOffset = calibration.InitialOffsets.Offsets.ToList().Last();
result = $"{initialOffset.Form},{initialOffset.EU},{initialOffset.MV}";
break;
}
break;
}
}
}
return result;
}
/// <summary>
/// This is for use when there are no elements in the <Settings> of a channel
/// </summary>
/// <param name="sensorLookup"></param>
/// <param name="channel"></param>
/// <param name="field"></param>
/// <returns></returns>
private string GetSettingFromSensorLookup(Dictionary<string, SensorData> sensorLookup, GroupChannel channel, DbOperations.TestSetups.SettingsFields field)
{
var result = string.Empty;
var key = string.Empty;
foreach (var entry in sensorLookup)
{
var sensorSerialNumber = string.Empty;
if (entry.Value.Bridge == SensorConstants.BridgeType.TOMDigital)
{
sensorSerialNumber = entry.Value.SerialNumber;
}
else
{
sensorSerialNumber = entry.Value.Comment;
}
if (sensorSerialNumber == channel.ChannelName)
{
key = entry.Key;
break;
}
}
if (!string.IsNullOrWhiteSpace(key))
{
switch (field)
{
case DbOperations.TestSetups.SettingsFields.FilterClass:
result = sensorLookup[key].FilterClass.ToString();
break;
case DbOperations.TestSetups.SettingsFields.Polarity:
result = sensorLookup[key].Polarity.ToString();
break;
case DbOperations.TestSetups.SettingsFields.LimitDuration:
result = sensorLookup[key].LimitDuration.ToString();
break;
case DbOperations.TestSetups.SettingsFields.Duration:
result = sensorLookup[key].DurationMS.ToString();
break;
case DbOperations.TestSetups.SettingsFields.Delay:
result = sensorLookup[key].DelayMS.ToString();
break;
case DbOperations.TestSetups.SettingsFields.OutputMode:
var intOutputMode = (int)sensorLookup[key].DigitalOutputMode;
result = intOutputMode.ToString();
break;
case DbOperations.TestSetups.SettingsFields.DigitalOutDelay:
result = sensorLookup[key].DigitalOutputDelayMS.ToString();
break;
case DbOperations.TestSetups.SettingsFields.DigitalOutDuration:
result = sensorLookup[key].DigitalOutputDurationMS.ToString();
break;
case DbOperations.TestSetups.SettingsFields.DigitalOutLimitDuration:
result = sensorLookup[key].DigitalOutputLimitDuration.ToString();
break;
case DbOperations.TestSetups.SettingsFields.SQMode:
var intSquibFireMode = (int)sensorLookup[key].SquibFireMode;
result = intSquibFireMode.ToString();
break;
case DbOperations.TestSetups.SettingsFields.SquibDelay:
result = sensorLookup[key].SquibFireDelayMS.ToString();
break;
case DbOperations.TestSetups.SettingsFields.SquibCurrent:
result = sensorLookup[key].SquibOutputCurrent.ToString();
break;
case DbOperations.TestSetups.SettingsFields.SquibDuration:
result = sensorLookup[key].SquibFireDurationMS.ToString();
break;
case DbOperations.TestSetups.SettingsFields.SquibLimitDuration:
result = sensorLookup[key].LimitSquibFireDuration.ToString();
break;
case DbOperations.TestSetups.SettingsFields.DIMode:
var intDigitalOutputMode = (int)sensorLookup[key].DigitalOutputMode;
result = intDigitalOutputMode.ToString();
break;
case DbOperations.TestSetups.SettingsFields.UserValue1:
result = sensorLookup[key].UserValue1.ToString();
break;
case DbOperations.TestSetups.SettingsFields.UserValue2:
result = sensorLookup[key].UserValue2.ToString();
break;
case DbOperations.TestSetups.SettingsFields.UserValue3:
result = sensorLookup[key].UserValue3.ToString();
break;
case DbOperations.TestSetups.SettingsFields.UartBaudRate:
result = sensorLookup[key].UartBaudRate.ToString();
break;
case DbOperations.TestSetups.SettingsFields.UartDataBits:
result = sensorLookup[key].UartDataBits.ToString();
break;
case DbOperations.TestSetups.SettingsFields.UartStopBits:
result = sensorLookup[key].UartStopBits.ToString();
break;
case DbOperations.TestSetups.SettingsFields.UartParity:
result = sensorLookup[key].UartParity.ToString();
break;
case DbOperations.TestSetups.SettingsFields.UartFlowControl:
result = sensorLookup[key].UartFlowControl.ToString();
break;
case DbOperations.TestSetups.SettingsFields.UartDataFormat:
result = sensorLookup[key].UartDataFormat.ToString();
break;
case DbOperations.TestSetups.SettingsFields.StreamOutUDPProfile:
result = sensorLookup[key].StreamOutUDPProfile.ToString();
break;
case DbOperations.TestSetups.SettingsFields.StreamOutUDPAddress:
result = sensorLookup[key].StreamOutUDPAddress.ToString();
break;
case DbOperations.TestSetups.SettingsFields.StreamOutUDPTimeChannelId:
result = sensorLookup[key].StreamOutUDPTimeChannelId.ToString();
break;
case DbOperations.TestSetups.SettingsFields.StreamOutUDPDataChannelId:
result = sensorLookup[key].StreamOutUDPDataChannelId.ToString();
break;
case DbOperations.TestSetups.SettingsFields.StreamOutUDPTmNSConfig:
result = sensorLookup[key].StreamOutUDPTmNSConfig.ToString();
break;
case DbOperations.TestSetups.SettingsFields.StreamOutIRIGTimeDataPacketIntervalMs:
result = sensorLookup[key].StreamOutIRIGTimeDataPacketIntervalMs.ToString();
break;
case DbOperations.TestSetups.SettingsFields.StreamOutTMATSIntervalMs:
result = sensorLookup[key].StreamOutTMATSIntervalMs.ToString();
break;
//33415 Voltage insertion channel should be half bridge
case DbOperations.TestSetups.SettingsFields.BridgeType:
result = sensorLookup[key].Bridge.ToString();
break;
}
}
return result;
}
/// <summary>
/// handles setting zero method properties from imported xml for a group channel for an embedded group
/// there is equivalent code in Group.ReadXml, but apparently embedded groups don't go through that
/// route in imports ...
/// 15270 Sensor Import does not import most channel settings
/// </summary>
private bool ProcessZeroMethod(string zeroMethod, string zeroStart, string zeroEnd,
IReadOnlyDictionary<string, Tuple<int, string, string>> dictionary, ref List<IChannelSetting> settings)
{
var bHasZeroMethodInXML = false;
if (!string.IsNullOrWhiteSpace(zeroMethod))
{
var tuple = dictionary[ChannelSettingBase.ZEROMETHOD];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3) { Value = zeroMethod });
bHasZeroMethodInXML = true;
}
if (!string.IsNullOrWhiteSpace(zeroStart))
{
var tuple = dictionary[ChannelSettingBase.ZEROMETHODSTART];
if (double.TryParse(zeroStart, NumberStyles.Any, CultureInfo.InvariantCulture,
out var d))
{
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3) { DoubleValue = d });
}
}
if (!string.IsNullOrWhiteSpace(zeroEnd))
{
var tuple = dictionary[ChannelSettingBase.ZEROMETHODEND];
if (double.TryParse(zeroEnd, NumberStyles.Any, CultureInfo.InvariantCulture,
out var d))
{
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3) { DoubleValue = d });
}
}
return bHasZeroMethodInXML;
}
/// <summary>
/// handles setting user value settings from imported xml for an embedded group channel
/// there is equivalent code in Group.ReadXml, but embedded groups dont' go through that route
/// 15270 Sensor Import does not import most channel settings
/// </summary>
private void ProcessUserValues(string userValue1, string userValue2, string userValue3,
IReadOnlyDictionary<string, Tuple<int, string, string>> dictionary, ref List<IChannelSetting> settings)
{
if (!string.IsNullOrWhiteSpace(userValue1))
{
var tuple = dictionary[ChannelSettingBase.USERVALUE1];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3)
{ Value = userValue1 });
}
if (!string.IsNullOrWhiteSpace(userValue2))
{
var tuple = dictionary[ChannelSettingBase.USERVALUE2];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3) { Value = userValue2 });
}
if (!string.IsNullOrWhiteSpace(userValue3))
{
var tuple = dictionary[ChannelSettingBase.USERVALUE3];
settings.Add(new ChannelSettingBase(tuple.Item1, tuple.Item2, tuple.Item3) { Value = userValue3 });
}
}
private string GetGroupRange(GroupChannel channel, IDictionary<string, IGroup> groupLookup)
{
foreach (var group in groupLookup)
{
if (group.Value.Name != channel.GroupName) { continue; }
foreach (var groupChannel in group.Value.GroupChannelList)
{
if ((groupChannel as GroupChannel).ChannelName != channel.ChannelName) { continue; }
foreach (var setting in groupChannel.ChannelSettings)
{
if (setting.SettingName == DbOperations.TestSetups.SettingsFields.Range.ToString())
{
return setting.Value;
}
}
}
}
return string.Empty;
}
#endregion READ FROM XML
#region XML TAGS
private const string TESTSETUP_ROOT = "TestSetup";
private const string DASLIST_ROOT = "DASList";
private const string TESTID_ROOT = "Id";
private const string DASHARDWARE_ROOT = "DASHardware";
private const string DAS_SERIALNUMBER = "SerialNumber";
private const string DAS_TESTSAMPLERATE = "SamplesPerSecond";
private const string DAS_ISCLOCKMASTER = "IsClockMaster";
private const string DAS_AAFRATE = "AntiAliasFilterRate";
private const string DAS_PTPDOMAINID = "PTPDomainId";
private const string ADDEDGROUPS_ROOT = "AddedGroups";
private const string SYSBUILTTESTOBJECTS_ROOT = "SysBuiltTestObjects";
private const string TESTOBJECT_ROOT = "TestObject";
private const string GROUP_ROOT = "Group";
private const string HARDWARE_LIST = "HardwareList";
private const string HARDWARE = "Hardware";
private const string CHANNEL_ROOT = "Channel";
private const string CHANNELSETTINGS_ROOT = "ChannelSettings";
private const string TESTOBJECTS_ROOT = "TestObjects";
private const string GROUPS_ROOT = "Groups";
private const string GRAPHS_ROOT = "Graphs";
private const string GRAPH_ROOT = "Graph";
private const string FIELDS_ROOT = "Fields";
private const string METADATAS_ROOT = "MetaDatas";
private const string METADATA_ROOT = "MetaData";
private const string HARDWAREOVERRIDE_ACTION = "Action";
private const string HARDWAREOVERRIDE_HID = "HID";
private const string HARDWAREOVERRIDE_ROOT = "HardwareOverride";
private const string HARDWAREOVERRIDES_ROOT = "HardwareOverrides";
private const string HARDWAREINCLUDES_ROOT = "HardwareIncludes";
private const string HARDWAREREMOVES_ROOT = "HardwareRemoves";
private const string HARDWARELIST_ROOT = "HWList";
private const string LEVELTRIGGERS_ROOT = "LevelTriggers";
private const string LEVELTRIGGER_ROOT = "LevelTrigger";
private const string LT_TESTOBJECTCHANNELID = "TestObjectChannelId";
private const string LT_GROUPCHANNELID = "GroupChannelId";
private const string LT_HARDWARECHANNELID = "HardwareChannelId";
private const string LT_SENSORSERIALNUMBER = "SensorSerialNumber";
private const string LT_LESSTHANTHRESHOLDEU = "LessThanValue";
private const string LT_LESSTHANENABLED = "LessThanEnabled";
private const string LT_GREATERTHANENABLED = "GreaterThanEnabled";
private const string LT_GREATERTHANTHRESHOLDEU = "GreaterThanValue";
private const string LT_TRIGGEROUTSIDE = "TriggerOutside";
private const string LT_TRIGGERINSIDE = "TriggerInside";
private const string LT_OUTSIDEUPPEREU = "OutsideUpperEU";
private const string LT_OUTSIDELOWEREU = "OutsideLowerEU";
private const string LT_INSIDEUPPEREU = "InsideUpperEU";
private const string LT_INSIDELOWEREU = "InsideLowerEU";
private const string CALCULATEDCHANNELS_ROOT = "CalculatedChannels";
private const string CALCULATEDCHANNEL_ROOT = "CalculatedChannel";
private const string CC_CALCULATEDCHANNELVALUE = "ISOCODE";
private const string CC_CFCFORINPUTCHANNELS = "CFCInputChannels";
private const string CC_CFCFOROUTPUTCHANNELS = "CFCOutput";
private const string CC_TESTSETUPNAME = "TestSetupName";
private const string CC_NAME = "Name";
private const string CC_INPUTCHANNELIDS = "InputChannelIds";
private const string CC_ID = "ID";
private const string CC_OPERATION = "Operation";
private const string TO_SERIALNUMBER = "TestObjectSerialNumber";
private const string CC_VIEWINREALTIME = "ViewInRealtime";
private const string CC_CLIPLENGTH = "ClipLength";
#endregion XML TAGS
/// <summary>
/// writes a test setup out to xml
/// </summary>
/// <param name="writer"></param>
public void WriteXML(ref System.Xml.XmlWriter writer)
{
writer.WriteStartElement(TESTSETUP_ROOT);
var f1 = Enum.GetValues(typeof(DbOperations.TestSetups.ChannelFields)).Cast<DbOperations.TestSetups.ChannelFields>().ToArray();//done
var f6 = Enum.GetValues(typeof(DbOperations.TestSetups.TestSetupObjectFields)).Cast<DbOperations.TestSetups.TestSetupObjectFields>().ToArray();//done
var testSetupGroupFieldsArray = Enum.GetValues(typeof(DbOperations.TestSetups.TestSetupGroupFields)).Cast<DbOperations.TestSetups.TestSetupGroupFields>().ToArray();//done
var f7 = Enum.GetValues(typeof(DbOperations.TestSetups.GraphFields)).Cast<DbOperations.TestSetups.GraphFields>().ToArray(); //done
var f2 = Enum.GetValues(typeof(DbOperations.TestSetups.Fields)).Cast<DbOperations.TestSetups.Fields>().ToArray();//done
var f3 = Enum.GetValues(typeof(DbOperations.TestSetups.TestObjectMetaDataFields)).Cast<DbOperations.TestSetups.TestObjectMetaDataFields>().ToArray();
//new element in v9
//15727 Building and Replacing Racks/Mods
writer.WriteStartElement(TESTID_ROOT);
writer.WriteString(Id.ToString());
writer.WriteEndElement();
#region DASList
if (DASSampleRateList.Count > 0)
{
writer.WriteStartElement(DASLIST_ROOT); //<DASList>
foreach (var pair in DASSampleRateList)
{
writer.WriteStartElement(DASHARDWARE_ROOT); //<DASHardware>
writer.WriteStartElement(DAS_SERIALNUMBER); //<SerialNumber>
writer.WriteString(pair.Key);
writer.WriteEndElement();
writer.WriteStartElement(DAS_TESTSAMPLERATE); //<SamplesPerSecond>
writer.WriteString(pair.Value.ToString(CultureInfo.InvariantCulture));
writer.WriteEndElement();
writer.WriteStartElement(DAS_ISCLOCKMASTER); //<IsClockMaster>
var key1 = pair.Key.ToLower();
var key2 = pair.Key.ToUpper();
if (DASClockMasterList.ContainsKey(key1))
{
writer.WriteString(DASClockMasterList[key1].ToString());
}
else if (DASClockMasterList.ContainsKey(key2))
{
writer.WriteString(DASClockMasterList[key2].ToString());
}
else { writer.WriteString(false.ToString()); }
writer.WriteEndElement();
writer.WriteStartElement(DAS_AAFRATE); //<AAFRate>
writer.WriteString(DASAAFRateList[pair.Key.ToString()].ToString());
writer.WriteEndElement();
writer.WriteStartElement(DAS_PTPDOMAINID); // <PTPDomainID>
if (!DASPTPDomainIDList.ContainsKey(pair.Key.ToString()))
{
writer.WriteString("1");
}
else
{
writer.WriteString(DASPTPDomainIDList[pair.Key.ToString()].ToString());
}
writer.WriteEndElement();
writer.WriteEndElement();
}
writer.WriteEndElement();
}
#endregion
#region Groups
writer.WriteStartElement(GROUPS_ROOT);
//foreach (var to in TestObjects)
foreach (var g in Groups)
{
writer.WriteStartElement(GROUP_ROOT);
// ReSharper disable once InconsistentNaming
//var isoTO = to.GetISOTestObject();
foreach (var toField in testSetupGroupFieldsArray)
{
if (toField == DbOperations.TestSetups.TestSetupGroupFields.SerialNumber) continue; //Changed to Name in 2.0
writer.WriteStartElement(toField.ToString());
switch (toField)
{
case DbOperations.TestSetups.TestSetupGroupFields.Name: writer.WriteString(g.Name); break; //Changed from SerialNumber in 2.0
case DbOperations.TestSetups.TestSetupGroupFields.DisplayName: writer.WriteString(g.DisplayName); break;
case DbOperations.TestSetups.TestSetupGroupFields.Description: writer.WriteString(g.Description); break;
//FB 41857 check for null Name to prevent crash
case DbOperations.TestSetups.TestSetupGroupFields.TestSetupName: writer.WriteString(Name?.Trim()); break;
case DbOperations.TestSetups.TestSetupGroupFields.DisplayOrder: writer.WriteString(g.DisplayOrder.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.TestSetupGroupFields.Position: writer.WriteString(g.Position); break;
case DbOperations.TestSetups.TestSetupGroupFields.TestObjectType: writer.WriteString(g.TestObject); break;
case DbOperations.TestSetups.TestSetupGroupFields.Id: writer.WriteString(g.Id.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.TestSetupGroupFields.StaticGroupId:
var staticGroupId = g.StaticGroupId == null ? string.Empty : g.StaticGroupId.ToString();
writer.WriteString(staticGroupId);
break;
default: throw new NotSupportedException("TestTemplate::WriteXML unsupported field: " + toField);
}
writer.WriteEndElement();
}
writer.WriteStartElement(HARDWARE_LIST);
foreach (var hardware in g.IncludedHardwareStringList)
{
writer.WriteStartElement(HARDWARE);
writer.WriteString(hardware);
writer.WriteEndElement(); //Hardware
}
writer.WriteEndElement(); //HardwareList
//foreach (var ch in isoTO.AllChannels)
var sensorLookup = new Dictionary<int, ISensorData>();
var sensors = SensorsCollection.SensorsList.GetAllSensors(false);
foreach (var s in sensors)
{
sensorLookup[s.DatabaseId] = s;
}
var channels = ChannelsForGroup[g];
foreach (var groupChannel in channels)
{
if (groupChannel.IsBlank()) { continue; }
writer.WriteStartElement(CHANNEL_ROOT);
if (groupChannel.DASId > 0 && groupChannel.DASChannelIndex >= 0)
{
var hardwareList = GetHardware();
groupChannel.Hardware = GetGroupChannelHardware(groupChannel.DASId, groupChannel.DASChannelIndex, hardwareList);
groupChannel.HardwareId = GetGroupChannelHardwareId(groupChannel.DASId, groupChannel.DASChannelIndex, hardwareList);
}
foreach (var f in f1)
{
writer.WriteStartElement(f.ToString());
switch (f)
{
case DbOperations.TestSetups.ChannelFields.ISOChannelName: writer.WriteString(groupChannel.IsoChannelName); break;
case DbOperations.TestSetups.ChannelFields.ISOCode: writer.WriteString(groupChannel.IsoCode); break;
case DbOperations.TestSetups.ChannelFields.UserChannelName: writer.WriteString(groupChannel.UserChannelName); break;
case DbOperations.TestSetups.ChannelFields.UserCode: writer.WriteString(groupChannel.UserCode); break;
case DbOperations.TestSetups.ChannelFields.Id:
writer.WriteString(groupChannel.Id.ToString(CultureInfo.InvariantCulture));
break;
case DbOperations.TestSetups.ChannelFields.DASId:
writer.WriteString(
groupChannel.DASId.ToString(CultureInfo.InvariantCulture));
break;
case DbOperations.TestSetups.ChannelFields.DASChannelIdx:
writer.WriteString(
groupChannel.DASChannelIndex.ToString(CultureInfo
.InvariantCulture));
break;
case DbOperations.TestSetups.ChannelFields.SensorId:
writer.WriteString(
groupChannel.SensorId.ToString(CultureInfo.InvariantCulture));
break;
case DbOperations.TestSetups.ChannelFields.TestSetupOrder:
writer.WriteString(
groupChannel.TestSetupOrder.ToString(CultureInfo
.InvariantCulture));
break;
case DbOperations.TestSetups.ChannelFields.GroupOrder:
writer.WriteString(
groupChannel.GroupChannelOrder.ToString(CultureInfo
.InvariantCulture));
break;
case DbOperations.TestSetups.ChannelFields.Disabled: writer.WriteString(false.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.ChannelFields.Settings:
foreach (var channelSetting in groupChannel.ChannelSettings)
{
//FB 13120 Do not export CFC setting to xml file
if (channelSetting.SettingName == "CFC")
{
continue;
}
writer.WriteStartElement(channelSetting.SettingName);
writer.WriteString(channelSetting.Value);
writer.WriteEndElement(); //channelSettingName (Range, etc.)
}
break;
default: throw new NotSupportedException("TestTemplate::WriteXML unsupported field: " + f);
}
writer.WriteEndElement();//f.ToString()
}
writer.WriteEndElement();//Channel
}
writer.WriteEndElement();//testobject
}
writer.WriteEndElement();//testobjects
#endregion TestObjects
#region Graphs
writer.WriteStartElement(GRAPHS_ROOT);
foreach (var g in TestGraphs)
{
writer.WriteStartElement(GRAPH_ROOT);
g.WriteXML(ref writer);
// writer.WriteStartElement(GRAPH_ROOT);
// foreach (var f in f7)
// {
// writer.WriteStartElement(f.ToString());
// switch (f)
// {
// case DbOperations.TestSetups.GraphFields.Channels: writer.WriteString(g.GetChannelsForSQL()); break;
// case DbOperations.TestSetups.GraphFields.DomainMax: writer.WriteString(g.DomainMax.ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
// case DbOperations.TestSetups.GraphFields.DomainMin: writer.WriteString(g.DomainMin.ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
// case DbOperations.TestSetups.GraphFields.GraphDescription: writer.WriteString(g.GraphDescription); break;
// case DbOperations.TestSetups.GraphFields.GraphName: writer.WriteString(g.GraphName); break;
// case DbOperations.TestSetups.GraphFields.LocalOnly: writer.WriteString(LocalOnly.ToString()); break;
// case DbOperations.TestSetups.GraphFields.RangeMax: writer.WriteString(g.RangeMax.ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
// case DbOperations.TestSetups.GraphFields.RangeMin: writer.WriteString(g.RangeMin.ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
// case DbOperations.TestSetups.GraphFields.TemplateName: writer.WriteString(Name); break;
// case DbOperations.TestSetups.GraphFields.Thresholds: writer.WriteString(g.GetThresholdsSQL()); break;
// case DbOperations.TestSetups.GraphFields.UseDomainMax: writer.WriteString(g.UseDomainMax.ToString()); break;
// case DbOperations.TestSetups.GraphFields.UseDomainMin: writer.WriteString(g.UseDomainMin.ToString()); break;
// case DbOperations.TestSetups.GraphFields.UseRangeMax: writer.WriteString(g.UseRangeMax.ToString()); break;
// case DbOperations.TestSetups.GraphFields.UseRangeMin: writer.WriteString(g.UseRangeMin.ToString()); break;
// case DbOperations.TestSetups.GraphFields.TestSetupName: writer.WriteString(Name); break;
// default: throw new NotSupportedException("TestTemplate::WriteXML unsupported field: " + f);
// }
// writer.WriteEndElement();//f.toString()
// }
writer.WriteEndElement();
}
writer.WriteEndElement();//graphs
#endregion Graphs
#region Fields
writer.WriteStartElement(FIELDS_ROOT);
foreach (var f in f2)
{
writer.WriteStartElement(f.ToString());
switch (f)
{
case DbOperations.TestSetups.Fields.AllowMissingSensors: writer.WriteString(AllowMissingSensors.ToString()); break;
case DbOperations.TestSetups.Fields.AllowSensorIdToBlankChannel: writer.WriteString(AllowSensorIdToBlankChannel.ToString()); break;
case DbOperations.TestSetups.Fields.AutomaticProgressionDelayMS: writer.WriteString(AutomaticProgressionDelayMS.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.AutomaticTestProgression: writer.WriteString(AutomaticProgression.ToString()); break;
case DbOperations.TestSetups.Fields.AutoVerifyChannels: writer.WriteString(AutoVerifyChannels.ToString()); break;
case DbOperations.TestSetups.Fields.CommonStatusLine: writer.WriteString(CommonLine.ToString()); break;
case DbOperations.TestSetups.Fields.CalibrationBehavior: writer.WriteString(CalibrationBehavior.ToString()); break;
case DbOperations.TestSetups.Fields.CustomerDetails: writer.WriteString((null != CustomerDetails) ? CustomerDetails.Name : ""); break;
case DbOperations.TestSetups.Fields.DownloadAll: writer.WriteString(DownloadAll.ToString()); break;
case DbOperations.TestSetups.Fields.DownloadFolder: writer.WriteString(DownloadFolder); break;
case DbOperations.TestSetups.Fields.Export: writer.WriteString(ViewExport.ToString()); break;
case DbOperations.TestSetups.Fields.AlignUDPToPPS: writer.WriteString(AlignUDPToPPS.ToString()); break;
case DbOperations.TestSetups.Fields.ExportFolder: writer.WriteString(ExportFolder); break;
case DbOperations.TestSetups.Fields.ExportFormat: writer.WriteString(((ulong)ExportFormats).ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.InvertStart: writer.WriteString(InvertStartRecordCompletion.ToString()); break;
case DbOperations.TestSetups.Fields.InvertTrigger: writer.WriteString(InvertTriggerCompletion.ToString()); break;
case DbOperations.TestSetups.Fields.IgnoreShortedStart: writer.WriteString(IgnoreShortedStartCompletion.ToString()); break;
case DbOperations.TestSetups.Fields.IgnoreShortedTrigger: writer.WriteString(IgnoreShortedTriggerCompletion.ToString()); break;
case DbOperations.TestSetups.Fields.LabDetails: writer.WriteString((null != LabDetails) ? LabDetails.Name : ""); break;
case DbOperations.TestSetups.Fields.LastModified: writer.WriteString(LastModified.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.LastModifiedBy: writer.WriteString(LastModifiedBy); break;
case DbOperations.TestSetups.Fields.LocalOnly: writer.WriteString(LocalOnly.ToString()); break;
case DbOperations.TestSetups.Fields.PostTestDiagnostics: writer.WriteString(PostTestDiagnosticsLevel.ToString()); break;
case DbOperations.TestSetups.Fields.PostTriggerSeconds: writer.WriteString(PostTriggerSeconds.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.PreTriggerSeconds: writer.WriteString(PreTriggerSeconds.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.NumberOfEvents: writer.WriteString(NumberOfEvents.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.WakeUpMotionTimeout: writer.WriteString(WakeUpMotionTimeout.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.ScheduledStartDateTime: writer.WriteString(RTCScheduleStartDateTime.ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.IntervalBetweenEventStartsMinutes: writer.WriteString(IntervalBetweenEventStartsMinutes.ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.StartWithEvent: writer.WriteString(StartWithEvent.ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.WakeUpWithMotion: writer.WriteString(WakeUpWithMotion.ToString(System.Globalization.CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.RealtimePlotCount: writer.WriteString(DefaultNumberRealtimeGraphs.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.RecordingMode: writer.WriteString(RecordingMode.ToString()); break;
case DbOperations.TestSetups.Fields.RequireConfirmationOnErrors: writer.WriteString(RequireUserConfirmationOnErrors.ToString()); break;
case DbOperations.TestSetups.Fields.ROIDownload: writer.WriteString(DoROIDownload.ToString()); break;
case DbOperations.TestSetups.Fields.RegionsOfInterest:
foreach (var roi in RegionsOfInterest)
{
writer.WriteStartElement("RegionOfInterest");
writer.WriteElementString("Suffix", roi.Suffix);
writer.WriteElementString("Start",
roi.Start.ToString(CultureInfo.InvariantCulture));
writer.WriteElementString("End",
roi.End.ToString(CultureInfo.InvariantCulture));
writer.WriteElementString("ChannelNames", String.Join(",", roi.ChannelNames));
writer.WriteElementString("ChannelIds", String.Join(",", roi.ChannelIds));
writer.WriteEndElement();
}
break;
case DbOperations.TestSetups.Fields.ROIEnd: writer.WriteString(ROIEnd.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.ROIStart: writer.WriteString(ROIStart.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.SameAsDownloadFolder: writer.WriteString(SameAsDownloadFolder.ToString()); break;
case DbOperations.TestSetups.Fields.SamplesPerSecond: writer.WriteString(SamplesPerSecondAggregate.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.TestEngineerDetails: writer.WriteString((null != TestEngineerDetails) ? TestEngineerDetails.Name : ""); break;
case DbOperations.TestSetups.Fields.WarnOnBatteryFail: writer.WriteString(WarnOnFailedBattery.ToString()); break;
case DbOperations.TestSetups.Fields.SetupDescription: writer.WriteString(Description); break;
case DbOperations.TestSetups.Fields.Settings: writer.WriteString(_settings.ToSerializeString()); break;
//FB 41857 check for null Name to prevent crash
case DbOperations.TestSetups.Fields.SetupName: writer.WriteString(Name?.Trim()); break;
case DbOperations.TestSetups.Fields.StrictDiagnostics: writer.WriteString(StrictDiagnostics.ToString()); break;
case DbOperations.TestSetups.Fields.TriggerCheckRealtime: writer.WriteString(TriggerCheckRealtime.ToString()); break;
case DbOperations.TestSetups.Fields.TriggerCheckStep: writer.WriteString(TriggerCheckStep.ToString()); break;
case DbOperations.TestSetups.Fields.TurnOffExcitation: writer.WriteString(TurnOffExcitation.ToString()); break;
case DbOperations.TestSetups.Fields.UploadData: writer.WriteString(UploadData.ToString()); break;
case DbOperations.TestSetups.Fields.UploadDataFolder: writer.WriteString(UploadFolder); break;
case DbOperations.TestSetups.Fields.UploadExportsOnly: writer.WriteString(UploadExportsOnly.ToString()); break;
case DbOperations.TestSetups.Fields.UseCustomerDetails: writer.WriteString(UseCustomerDetails.ToString()); break;
case DbOperations.TestSetups.Fields.UseTestEngineerDetails: writer.WriteString(UseTestEngineerDetails.ToString()); break;
case DbOperations.TestSetups.Fields.UseLabDetails: writer.WriteString(UseLabratoryDetails.ToString()); break;
case DbOperations.TestSetups.Fields.VerifyChannels: writer.WriteString(VerifyChannels.ToString()); break;
case DbOperations.TestSetups.Fields.VerifyChannelsDelayMS: writer.WriteString((AutoVerifyDelaySeconds * 1000D).ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.Fields.ViewDiagnostics: writer.WriteString(ViewDiagnostics.ToString()); break;
case DbOperations.TestSetups.Fields.ViewDownloadAll: writer.WriteString(ViewDownloadAll.ToString()); break;
case DbOperations.TestSetups.Fields.ViewRealtime: writer.WriteString(ViewRealtime.ToString()); break;
case DbOperations.TestSetups.Fields.ViewROIDownload: writer.WriteString(ViewROIDownload.ToString()); break;
case DbOperations.TestSetups.Fields.ErrorMessage: writer.WriteString(CompletionErrorMessage); break;
case DbOperations.TestSetups.Fields.Dirty: writer.WriteString(IsDirty.ToString()); break;
case DbOperations.TestSetups.Fields.Complete: writer.WriteString(IsComplete.ToString()); break;
case DbOperations.TestSetups.Fields.UserTags: writer.WriteString(GetTagsAsCommaSeparatedString(DbOperations.TagsGet)); break;
case DbOperations.TestSetups.Fields.DoAutoArm: writer.WriteString(DoAutoArm.ToString()); break;
case DbOperations.TestSetups.Fields.DoEnableRepeat: writer.WriteString(DoEnableRepeat.ToString()); break;
case DbOperations.TestSetups.Fields.DoStreaming: writer.WriteString(DoStreaming.ToString()); break;
case DbOperations.TestSetups.Fields.CheckoutMode: writer.WriteString(CheckoutMode.ToString()); break;
case DbOperations.TestSetups.Fields.QuitTestWithoutWarning: writer.WriteString(QuitTestWithoutWarning.ToString()); break;
case DbOperations.TestSetups.Fields.SuppressMissingSensorsWarning: writer.WriteString(SuppressMissingSensorsWarning.ToString()); break;
case DbOperations.TestSetups.Fields.NotAllChannelsViewer: writer.WriteString(NotAllChannelsViewer.ToString()); break;
case DbOperations.TestSetups.Fields.NotAllChannelsRealTime: writer.WriteString(NotAllChannelsRealTime.ToString()); break;
case DbOperations.TestSetups.Fields.ISFFile: writer.WriteString(ISFFile); break;
case DbOperations.TestSetups.Fields.ClockSyncProfileMaster: writer.WriteString(ClockSyncProfileMaster.ToString()); break;
case DbOperations.TestSetups.Fields.ClockSyncProfileSlave: writer.WriteString(ClockSyncProfileSlave.ToString()); break;
case DbOperations.TestSetups.Fields.ExtraProperties:
foreach (var exp in ExtraProperties)
{
writer.WriteStartElement("ExtraProperty");
writer.WriteElementString("Key", exp.Key);
writer.WriteElementString("Value", exp.Value);
writer.WriteEndElement();
}
break;
case DbOperations.TestSetups.Fields.MeasureSquibResistancesStep: writer.WriteString(MeasureSquibResistancesStep.ToString()); break;
case DbOperations.TestSetups.Fields.TestSetupUniqueId:
if (TestSetupUniqueId == null)
{
TestSetupUniqueId = Guid.NewGuid().ToString();
}
writer.WriteString(TestSetupUniqueId.ToString()); break;
default: throw new NotSupportedException("TestTemplate::WriteXML unsupported field: " + f);
}
writer.WriteEndElement();//f.ToString()
}
writer.WriteEndElement();//fields
#endregion Fields
#region HardwareOverrides
if (AddedHardware.Any())
{
writer.WriteStartElement(HARDWAREINCLUDES_ROOT);
var sb = new StringBuilder();
foreach (var id in AddedHardware)
{
if (sb.Length > 0)
{
sb.Append(",");
}
sb.Append(id.ToString(CultureInfo.InvariantCulture));
}
writer.WriteAttributeString(HARDWARELIST_ROOT, sb.ToString());
writer.WriteEndElement();
}
if (RemovedHardware.Any())
{
writer.WriteStartElement(HARDWAREREMOVES_ROOT);
var sb = new StringBuilder();
foreach (var id in RemovedHardware)
{
if (sb.Length > 0)
{
sb.Append(",");
}
sb.Append(id.ToString(CultureInfo.InvariantCulture));
}
writer.WriteAttributeString(HARDWARELIST_ROOT, sb.ToString());
writer.WriteEndElement();
}
if (HardwareOverrides.Count > 0)
{
writer.WriteStartElement(HARDWAREOVERRIDES_ROOT);
using (var e = HardwareOverrides.GetEnumerator())
{
while (e.MoveNext())
{
writer.WriteStartElement(HARDWAREOVERRIDE_ROOT);
writer.WriteAttributeString(HARDWAREOVERRIDE_HID, e.Current.Value.HardwareId);
writer.WriteAttributeString(HARDWAREOVERRIDE_ACTION, e.Current.Value.Action.ToString());
writer.WriteEndElement(); //hardwareoverride_root
}
}
writer.WriteEndElement();//hardware overrides root
}
#endregion HardwareOverrides
#region CalculatedChannels
if (CalculatedChannels.Count > 0)
{
writer.WriteStartElement(CALCULATEDCHANNELS_ROOT);
foreach (var cc in CalculatedChannels)
{
writer.WriteStartElement(CALCULATEDCHANNEL_ROOT);
writer.WriteAttributeString(CC_CALCULATEDCHANNELVALUE, cc.CalculatedValueCode);
writer.WriteAttributeString(CC_CFCFORINPUTCHANNELS, cc.CFCForInputChannels);
writer.WriteAttributeString(CC_CFCFOROUTPUTCHANNELS, cc.ChannelFilterClassForOutput);
writer.WriteAttributeString(CC_ID, cc.Id.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString(CC_INPUTCHANNELIDS, string.Join(CultureInfo.InvariantCulture.TextInfo.ListSeparator, cc.InputChannelIds));
writer.WriteAttributeString(CC_NAME, cc.Name);
writer.WriteAttributeString(CC_OPERATION, cc.Operation.ToString());
writer.WriteAttributeString(CC_TESTSETUPNAME, cc.TestSetupName);
writer.WriteAttributeString(CC_VIEWINREALTIME, cc.ViewInRealtime.ToString());
writer.WriteAttributeString(CC_CLIPLENGTH, cc.ClipLength.ToString(CultureInfo.InvariantCulture));
writer.WriteEndElement();//CALCULATEDCHANNEL_ROOT
}
writer.WriteEndElement();//CALCULATEDCHANNELS_ROOT
}
#endregion CalculatedChannels
#region LevelTriggers
if (LevelTriggerChannels.Count > 0)
{
writer.WriteStartElement(LEVELTRIGGERS_ROOT);
using (var e = LevelTriggerChannels.GetEnumerator())
{
while (e.MoveNext())
{
//shouldn't get here, but if we do, don't die...
var lt = e.Current.Value;
if (lt.GroupChannel == null) { continue; }
writer.WriteStartElement(LEVELTRIGGER_ROOT);
writer.WriteAttributeString(LT_GROUPCHANNELID, lt.GroupChannel.Id.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString(LT_HARDWARECHANNELID, lt.HardwareChannelId);
writer.WriteAttributeString(LT_SENSORSERIALNUMBER, lt.SensorSerialNumber);
writer.WriteAttributeString(LT_GREATERTHANENABLED,
lt.GreaterThanEnabled.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString(LT_GREATERTHANTHRESHOLDEU,
lt.GreaterThanThresholdEU.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString(LT_LESSTHANENABLED,
lt.LessThanEnabled.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString(LT_LESSTHANTHRESHOLDEU,
lt.LessThanThresholdEU.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString(LT_TRIGGERINSIDE,
lt.TriggerBetweenBounds.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString(LT_TRIGGEROUTSIDE,
lt.TriggerOutsideBounds.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString(LT_INSIDELOWEREU,
lt.InsideLowerLevelEU.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString(LT_INSIDEUPPEREU,
lt.InsideUpperLevelEU.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString(LT_OUTSIDELOWEREU,
lt.OutsideLowerLevelEU.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString(LT_OUTSIDEUPPEREU,
lt.OutsideUpperLevelEU.ToString(CultureInfo.InvariantCulture));
writer.WriteEndElement(); //LEVELTRIGGER_ROOT
}
}
writer.WriteEndElement();//LEVELTRIGGERS_ROOT
}
#endregion LevelTriggers
#region MetaDatas
writer.WriteStartElement(METADATAS_ROOT);
var testMeta = GetTestMetaData();
if (!string.IsNullOrWhiteSpace(testMeta.TestObject.ToString()))
{
foreach (var prop in testMeta.Properties)
{
writer.WriteStartElement(METADATA_ROOT);
foreach (var f in f3)
{
switch (f)
{
case DbOperations.TestSetups.TestObjectMetaDataFields.Optional: writer.WriteAttributeString(f.ToString(), prop.IsOptional.ToString()); break;
case DbOperations.TestSetups.TestObjectMetaDataFields.PropName: writer.WriteAttributeString(f.ToString(), prop.Name); break;
case DbOperations.TestSetups.TestObjectMetaDataFields.PropValue: writer.WriteAttributeString(f.ToString(), prop.Value); break;
//FB 41857 check for null Name to prevent crash
case DbOperations.TestSetups.TestObjectMetaDataFields.SetupName: writer.WriteAttributeString(f.ToString(), Name?.Trim()); break;
case DbOperations.TestSetups.TestObjectMetaDataFields.TestObject: writer.WriteAttributeString(f.ToString(), testMeta.TestObject.ToString()); break;
case DbOperations.TestSetups.TestObjectMetaDataFields.Version: writer.WriteAttributeString(f.ToString(), prop.Version.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.TestObjectMetaDataFields.ISOTestObject: break;//ignore this field, per AF is covered by testobject field
case DbOperations.TestSetups.TestObjectMetaDataFields.TestSetupName: break;
default: throw new NotSupportedException("TestTemplate::WriteXML unsupported field: " + f);
}
}
writer.WriteEndElement();
}
}
var toMetaDatas = GetMetaData();
foreach (var toMetaData in toMetaDatas)
{
// FB 17951 Prevent empty TestObject entry
if (string.IsNullOrWhiteSpace(toMetaData.TestObject.ToString()))
{
continue;
}
foreach (var prop in toMetaData.Properties)
{
writer.WriteStartElement(METADATA_ROOT);
foreach (var f in f3)
{
switch (f)
{
case DbOperations.TestSetups.TestObjectMetaDataFields.Optional: writer.WriteAttributeString(f.ToString(), prop.IsOptional.ToString()); break;
case DbOperations.TestSetups.TestObjectMetaDataFields.PropName: writer.WriteAttributeString(f.ToString(), prop.Name); break;
case DbOperations.TestSetups.TestObjectMetaDataFields.PropValue: writer.WriteAttributeString(f.ToString(), prop.Value); break;
case DbOperations.TestSetups.TestObjectMetaDataFields.SetupName: writer.WriteAttributeString(f.ToString(), Name); break;
case DbOperations.TestSetups.TestObjectMetaDataFields.TestObject: writer.WriteAttributeString(f.ToString(), toMetaData.TestObject.ToString()); break;
case DbOperations.TestSetups.TestObjectMetaDataFields.Version: writer.WriteAttributeString(f.ToString(), prop.Version.ToString(CultureInfo.InvariantCulture)); break;
case DbOperations.TestSetups.TestObjectMetaDataFields.TestSetupName: break;
case DbOperations.TestSetups.TestObjectMetaDataFields.ISOTestObject: break;
default: throw new NotSupportedException("TestTemplate::WriteXML unsupported field: " + f);
}
}
writer.WriteEndElement();
}
}
writer.WriteEndElement();
#endregion MetaDatas
WriteTSRAirSettings(ref writer);
writer.WriteEndElement();//testsetup
}
#endregion XML
private string GetGroupChannelHardware(int dasId, int dasChannelIndex, DASHardware[] hardwareList)
{
var matches = from hw in hardwareList where hw.DASId == dasId select hw;
if (!matches.Any()) { return string.Empty; }
var match = matches.First();
if (dasChannelIndex < 0 || dasChannelIndex >= match.Channels.Length) { return string.Empty; }
return match.Channels[dasChannelIndex]?.ToString(hardwareList);
}
private string GetGroupChannelHardwareId(int dasId, int dasChannelIndex, DASHardware[] hardwareList)
{
var matches = from hw in hardwareList where hw.DASId == dasId select hw;
if (!matches.Any()) { return string.Empty; }
var match = matches.First();
if (dasChannelIndex < 0 || dasChannelIndex >= match.Channels.Length) { return string.Empty; }
return match.Channels[dasChannelIndex]?.GetId();
}
public void ReloadGroupsMemoryOnly()
{
ReloadGroups(true);
}
/// <summary>
/// reloads static groups from list
/// </summary>
public void ReloadGroups(bool bMemoryOnly)
{
//if the groups aren't loaded yet, well we don't need to reload them because they'll automatically
//be loaded before we need them anyhow
if (!IsLoaded) { return; }
var addedGroups = new List<TestTestObject>();
var staticGroups = new List<TestTestObject>();
var allGroups = new List<TestTestObject>();
allGroups.AddRange(TestObjects);
allGroups.AddRange(AddedGroups);
SetTestObjects(bMemoryOnly, staticGroups.ToArray());
_addedGroups = new List<TestTestObject>(addedGroups.ToArray());
}
public bool CheckForIEPE()
{
var channels = GetChannels();
foreach (var ch in channels)
{
if (ch.IsBlank()) { continue; }
if (ch.IsDisabled) { continue; }
if (ch.IsDigitalIn || ch.IsDigitalOut || ch.IsSquib) { continue; }
if (ch.SensorValid)
{
var sd = GetSensor(ch);
if (null != sd)
{
if (sd.Bridge == SensorConstants.BridgeType.IEPE) { return true; }
}
}
}
return false;
}
/// <summary>
/// returns whether there is a TOM in the test setup or not
/// </summary>
/// <returns></returns>
public bool CheckForTOM()
{
var hardware = GetHardware();
foreach (var h in hardware)
{
if (h.IsTOM())
{
return true;
}
}
return false;
}
/// <summary>
/// returns whether there is a TOM with channels in use in the test setup or not
/// </summary>
/// <returns></returns>
public bool CheckForTOMInTest()
{
var hardware = GetHardware();
foreach (var h in hardware)
{
switch (h.GetHardwareTypeEnum())
{
case HardwareTypes.SLICE2_SLT:
case HardwareTypes.SLICE2_TOM:
case HardwareTypes.TDAS_Pro_Rack:
case HardwareTypes.TDAS_LabRack:
if (h.Channels.Any(c =>
(c.IsSupportedBridgeType(SensorConstants.BridgeType.SQUIB) ||
c.IsSupportedBridgeType(SensorConstants.BridgeType.TOMDigital)) &&
(c.Sensor != null)))
{
return true;
}
break;
}
}
return false;
}
/// <summary>
/// returns true if there are any analog channels on the hardware
/// </summary>
/// <param name="h">object to check</param>
/// <returns>true if contains an analog channel, false otherwise</returns>
private bool CheckForAnalog(DASHardware h)
{
if (!h.IsNonDistributorHardware) { return false; }
switch (h.GetHardwareTypeEnum())
{
case HardwareTypes.G5INDUMMY:
//case HardwareTypes.G5IPORT:
case HardwareTypes.G5VDS:
case HardwareTypes.SLICE1_G5Stack:
case HardwareTypes.Ribeye:
case HardwareTypes.RibeyeLED:
//do contain an analog, return true right away
return true;
case HardwareTypes.SLICE2_DIM:
case HardwareTypes.SLICE2_SLD:
case HardwareTypes.SLICE2_TOM:
case HardwareTypes.SLICE2_SLT:
break;//don't contain analog, keep going and look for analog
default:
//not sure, have to check channels...
if (Array.Exists(h.Channels, c => c.IsSupportedBridgeType(SensorConstants.BridgeType.FullBridge) ||
c.IsSupportedBridgeType(SensorConstants.BridgeType.IEPE)))
{
return true;
}
break;
}
return false;
}
/// <summary>
/// returns whether there is an analog channel in the test or not
/// </summary>
/// <returns></returns>
public bool CheckForAnalog()
{
foreach (var group in Groups)
{
if (ChannelsForGroup.ContainsKey(group))
{
var channels = ChannelsForGroup[group];
foreach (var ch in channels)
{
if (ch.IsBlank() || ch.IsDisabled || !ch.SensorValid) { continue; }
var sensor = GetSensor(ch);
if (null != sensor)
{
switch (sensor.Bridge)
{
case SensorConstants.BridgeType.SQUIB:
case SensorConstants.BridgeType.TOMDigital:
case SensorConstants.BridgeType.DigitalInput:
continue;
case SensorConstants.BridgeType.IEPE:
case SensorConstants.BridgeType.QuarterBridge:
case SensorConstants.BridgeType.HalfBridge:
case SensorConstants.BridgeType.FullBridge:
case SensorConstants.BridgeType.HalfBridge_SigPlus:
case SensorConstants.BridgeType.RTC:
return true;
}
}
}
}
}
return false;
}
/// <summary>
/// sets the dirty flag
/// does NOT set the flag in the database, so this should only be called when the flag needs to be set in memory
/// (for instance during initialization)
/// </summary>
/// <param name="bDirty"></param>
public void SetIsDirty(bool bDirty)
{
Dirty = bDirty;
}
/// <summary>
/// sets the complete flag
/// does not set the flag in the database, so this should only be called when the flag needs to be set in memory
/// (for instance during initialization)
/// </summary>
/// <param name="bComplete"></param>
public void SetIsComplete(bool bComplete)
{
base.IsComplete = bComplete;
}
/// <summary>
/// sets the completion error message.
/// does not set the field in the db, so this should only be called when the information nets to be set in memory and not the db
/// (for instance during initialization)
/// </summary>
/// <param name="msg"></param>
public void SetCompletionErrorMessage(string msg)
{
ErrorMessage = msg;
}
public int CompareTo(TestTemplate right)
{
if (null == right) { return 1; }
var r = string.Compare(Name, right.Name, StringComparison.Ordinal);
return 0 == r ? LastModified.CompareTo(right.LastModified) : r;
}
public TestTestObject GetTestTestObject(string testObjectSerial)
{
foreach (var tto in TestObjects)
{
if (tto.SerialNumber == testObjectSerial) { return tto; }
}
return Array.Find(AddedGroups, addedGroup => addedGroup.SerialNumber == testObjectSerial);
}
public double GetSampleRateForEmbeddedHardware(DASHardware h, DFConstantsAndEnums.ModuleType type)
{
switch (type)
{
case DFConstantsAndEnums.ModuleType.EmbeddedAngularAccel:
case DFConstantsAndEnums.ModuleType.EmbeddedAngularRate:
return AngularRate;
case DFConstantsAndEnums.ModuleType.EmbeddedLinearAccelLowG:
return LowgLinearAccRate;
case DFConstantsAndEnums.ModuleType.EmbeddedLinearAccelHighG:
return HighgLinearAccRate;
case DFConstantsAndEnums.ModuleType.EmbeddedAtmospheric:
return TemperatureHumidityPressureRate;
case DFConstantsAndEnums.ModuleType.EmbeddedClockSecondsAndMarker:
case DFConstantsAndEnums.ModuleType.EmbeddedClockNanosAndPad:
return 0;
default:
return GetSampleRateForHardware(h);
}
}
public double GetSampleRateForHardware(DASHardware h)
{
if (_dasSettings.ContainsKey(h.SerialNumber))
{
return _dasSettings[h.SerialNumber].SampleRate;
}
if (!DASSampleRateList.ContainsKey(h.SerialNumber))
{
DASSampleRateList[h.SerialNumber] = SamplesPerSecondAggregate;
}
return DASSampleRateList[h.SerialNumber];
}
public double GetSampleRateForHardware(string h)
{
return !_dasSettings.ContainsKey(h) ? DASSampleRateList[h] : _dasSettings[h].SampleRate;
}
public void SetSampleRateForHardware(DASHardware h, double d)
{
if (!_dasSettings.ContainsKey(h.SerialNumber)) { _dasSettings[h.SerialNumber] = CreateDASSettings(h); }
_dasSettings[h.SerialNumber].SampleRate = d;
}
public float GetAAFForHardware(IDASCommunication das)
{
return (float)(!_dasSettings.ContainsKey(das.SerialNumber) ? DASAAFRateList[das.SerialNumber] : _dasSettings[das.SerialNumber].HardwareAAF);
}
public float GetAAFForHardware(IDASCommunication das, int sps)
{
switch (das.GetHardwareType())
{
case HardwareTypes.DIM:
case HardwareTypes.G5INDUMMY:
case HardwareTypes.G5VDS:
case HardwareTypes.SIM:
case HardwareTypes.TDAS_Pro_Rack:
case HardwareTypes.TDAS_LabRack:
case HardwareTypes.TOM:
return GetAAFForHardware(SerializableAAF.DAS_TYPE.TDAS, sps);
default:
return GetAAFForHardware(SerializableAAF.DAS_TYPE.SLICE, sps);
}
}
/// <summary>
/// returns the Anti-Alias Filter (AAF) for the DAS in question
/// this is dependent on the sample rate for the hardware and a ratio in the config file
/// (RealtimeSampleRateAAFilterRatio)
/// </summary>
/// <param name="das"></param>
/// <returns></returns>
public float GetRealtimeAAFForHardware(IDASCommunication idas, double samplerate)
{
if (DataModelSettings.SLICETurnOffAAFRealtime && DFConstantsAndEnums.SupportsTurnOffAAFRealtime(idas))
{
return Constants.SLICE2_NO_AAF_REALTIME_RATE;
}
//for now there is no additional work done
if (0 == DataModelSettings.RealtimeSampleRateAAFilterRatio) { return Convert.ToSingle(samplerate); }
return (float)samplerate / DataModelSettings.RealtimeSampleRateAAFilterRatio;
}
public float GetAAFForHardware(DASHardware h)
{
return (float)(!_dasSettings.ContainsKey(h.SerialNumber) ? DASAAFRateList[h.SerialNumber] : _dasSettings[h.SerialNumber].HardwareAAF);
}
/// <summary>
/// returns the anti alias filter for a given simplehardware and sample rate
/// </summary>
private static float GetAAFForHardware(SimpleHardware simpleH, int sps)
{
var dasType = (HardwareTypes)simpleH.DASType;
return GetAAFForHardware(dasType, sps);
}
/// <summary>
/// returns the hardware rate given a hardware type and a sample rate
/// </summary>
public static float GetAAFForHardware(HardwareTypes hwType, int sps)
{
switch (hwType)
{
case HardwareTypes.DIM:
case HardwareTypes.G5INDUMMY:
case HardwareTypes.G5VDS:
case HardwareTypes.SIM:
case HardwareTypes.TDAS_Pro_Rack:
case HardwareTypes.TDAS_LabRack:
case HardwareTypes.TOM:
return GetAAFForHardware(SerializableAAF.DAS_TYPE.TDAS, sps);
default:
return GetAAFForHardware(SerializableAAF.DAS_TYPE.SLICE, sps);
}
}
/// <summary>
/// returns a hardware anti alias filter rate given a DASHardware and a sample rate
/// </summary>
public static float GetAAFForHardware(DASHardware h, int sps)
{
return GetAAFForHardware(h.DASTypeEnum, sps);
}
public static float GetAAFForHardware(SerializableAAF.DAS_TYPE dasType, int sps)
{
return Convert.ToSingle(SerializedSettings.GetAAFException(dasType, sps));
}
public void SetAAFRateForHardware(DASHardware h, double d)
{
if (!_dasSettings.ContainsKey(h.SerialNumber)) { _dasSettings[h.SerialNumber] = CreateDASSettings(h); }
_dasSettings[h.SerialNumber].HardwareAAF = d;
}
public static int GetSamplesPerPacketForHardware(int sps)
{
return Convert.ToInt32(SerializedSettings.GetSamplesPerPacket(sps));
}
private DASSettings CreateDASSettings(DASHardware h)
{
//just fill with all defaults for now, in the future we will probably want better filled in values,
//but for now I'm only implementing the samplerate portion of the problem.
return new DASSettings
{
DASSerialNumber = h.SerialNumber,
BatteryCheck = true,
BatteryVoltageMax = -1,
BatteryVoltageMin = -1,
ExcitationWarmupTimeMS = -1,
HardwareAAF = -1,
InputVoltageMax = -1,
InputVoltageMin = -1,
PostTriggerSeconds = PostTriggerSeconds,
PreTriggerSeconds = PreTriggerSeconds,
SampleRate = -1,
StatusLineCheck = true
};
}
public void SetDefaultSetupFile()
{
SetupFile = Defaults.GetUserSettingValueString(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.LastRunTestSetup);
}
/// <summary>
/// calculates whether the test setup is complete or not
/// will cause the test setup to be loaded if it is not yet
/// does not unload the test setup
/// </summary>
public void CalculateIsComplete(bool bSetInDb = true)
{
var eventAggregator = ContainerLocator.Container.Resolve<IEventAggregator>();
eventAggregator.GetEvent<ProgressBarEvent>().Publish(new ProgressBarEventArg()
{
SetText = true,
ProgressBarText =
$"{StringResources.Export_StatusValidating} {StringResources.Test} {Name}"
});
bool bNeedToUnload = false;
if (!IsLoaded)
{
bNeedToUnload = true;
Load();
}
var errorMessage = string.Empty;
var errors = new List<string>();
var warnings = new List<string>();
var strictness = QuickSensorCheck ? StrictLevel.CheckoutOnly : StrictLevel.UpdateTable;
var res = Validate(ref errors, ref warnings, false, this, true, strictness, true, true, false);
if (errors.Count > MAX_ERRORS_TO_DISPLAY)
{
errorMessage = $"{string.Join(Environment.NewLine, errors.ToArray(), 0, MAX_ERRORS_TO_DISPLAY)}{Environment.NewLine}{string.Format(StringResources.TestTemplate_MoreErrors, (errors.Count - MAX_ERRORS_TO_DISPLAY))}";
}
else if (errors.Count > 0) { errorMessage = string.Join(Environment.NewLine, errors.ToArray()); }
if (!res) { IsComplete = false; }
//FB14010: some warnings are OK for saving, but not for running tests
var hasIncompleteWarnings = warnings.Exists(warning => Array.Exists(_incompleteWarnings, incomplete => Array.TrueForAll(Regex.Split(incomplete, "{\\d+}"), inc => warning.Contains(inc))));
IsComplete = errors.Count <= 0 && !hasIncompleteWarnings;
ErrorMessage = errorMessage;
Dirty = false;
if (bSetInDb)
{
_ = DbOperations.TestSetupsMarkIsCompleteIsDirty(Name, Dirty, base.IsComplete, ErrorMessage);
}
if (bNeedToUnload)
{
UnLoad();
}
}
public void CheckSensorCalDates()
{
var sensorCalPolicy = CalibrationPolicy.GetCalibrationPolicy();
if (sensorCalPolicy.SelectedCalPolicy != SensorConstants.SensorCalPolicy.DONT_ALLOW)
{ //well if the problem before was an out of date sensor, reset it
if (CompletionErrorMessage.Contains(StringResources.OverdueSensors_CalibrationDateOverdueOrNear)) { SetIsDirty(true); }
}
else
{
var bWeLoadedIt = false;
if (!IsLoaded) { Load(); bWeLoadedIt = true; }
var bHaveAnOutofDateSensor = false;
var groups = new List<TestObject>(TestObjects);
groups.AddRange(AddedGroups);
foreach (var g in groups)
{
var isoTo = g.GetISOTestObject();
if ((from ch in isoTo.AllChannels
where ch.Required
where !string.IsNullOrWhiteSpace(ch.SensorSerialNumber)
select GetSensor(ch.SensorSerialNumber, g.SerialNumber, ch.Name) into s
where null != s
where !s.IsDigitalInput() && !s.IsDigitalOutput() && !s.IsSquib()
let sc = SensorCalibrationList.GetLatestCalibrationBySerialNumber(s)
where null == sc || s.GetDueDate(sc) < DateTime.Now.Date
select s).Any())
{
bHaveAnOutofDateSensor = true;
}
if (bHaveAnOutofDateSensor) { break; }
}
if (bHaveAnOutofDateSensor && sensorCalPolicy.SelectedCalPolicy == SensorConstants.SensorCalPolicy.DONT_ALLOW)
{ SetIsDirty(true); }
if (bWeLoadedIt) { UnLoad(); }
}
}
/// <summary>
/// marks a test setup as unchecked by setting the dirty flag, which means the next time completion is checked it will be calculated again
/// this function will change that flag in the database immediately
/// </summary>
public void MarkIsCompleteUnchecked(bool skipMemoryCheck = false)
{
IsComplete = false;
Dirty = true;
ErrorMessage = string.Empty;
if (string.IsNullOrEmpty(Name)) { return; }
_ = DbOperations.TestSetupsMarkIsCompleteIsDirty(Name, true, false, ErrorMessage);
}
public void ClearOverrides()
{
HardwareOverrides?.Clear();
}
/// <summary>
/// frees up the memory assigned during Load, this includes channels, groups, meta data, etc
/// various things may cause us to load the information and hold the information for some setups,
/// but in general we want to unload it if we don't need it
/// </summary>
public void UnLoad()
{
_bIsLoaded = false;
_testObjects?.Clear();
_addedGroups?.Clear();
TestObjectsAndAddedGroupsList?.Clear();
_channelKeysInOrder?.Clear();
lock (ChannelLookupLock)
{
_channelLookup?.Clear();
}
_checkedDASList?.Clear();
_dasChannelNumberToAbsoluteNumber?.Clear();
_dasLookup?.Clear();
_dasSettings?.Clear();
_filterLookup?.Clear();
_hardwareChannelsInOrder?.Clear();
_metaDataLookup?.Clear();
lock (SensorLock)
{
SensorLookup?.Clear();
}
_sessionOpen?.Clear();
_test = null;
_testGraphs?.Clear();
_testSetupMeta?.Clear();
HardwareOverrides?.Clear();
LevelTriggerChannels?.Clear();
}
/// <summary>
/// signifies if the test setup is being used for a quick checkout
/// quick checkout tests are not stored and are run time only
/// </summary>
public bool IsQuickCheckout { get; set; }
public void Load(bool fromDB = false)
{
//13443 Quick checkout tile not functional
//don't load quick check tests, they aren't stored ...
if (IsQuickCheckout) { return; }
Groups.Clear();
ChannelsForGroup.Clear();
LoadFromDb();
//Check for the possibility of a Test Setup that was imported from an earlier release that
//didn't yet have the concept of multiple ROIs
var settings = TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id);
if ((RegionsOfInterest.Count() == 1) &&
(RegionsOfInterest[0].Suffix == "") &&
(RegionsOfInterest[0].Start == settings.DefaultROIStart) &&
(RegionsOfInterest[0].End == settings.DefaultROIEnd) &&
(RegionsOfInterest[0].IsDefault == true) &&
(RegionsOfInterest[0].IsEnabled)
//The above looks like a NULL RegionsOfInterest field was found in the Test Setups table, but let's make sure
&&
((RegionsOfInterest[0].Start != ROIStart) || (RegionsOfInterest[0].End != ROIEnd))
)
{
RegionsOfInterest = new BindingList<IRegionOfInterest>
{
new RegionOfInterest("", false, ROIStart, ROIEnd)
};
}
}
public IISOHardware[] GetAllCachedHardware()
{
return new IISOHardware[0];
}
/// <summary>
/// this function removes specific hardware from the cache
/// this is a 3 step process,
/// 1) remove from _hardwareFromBinary, which is a list of hardware from the TestSetupXML
/// 2) update the TestSetupXML to also remove the hardware in question
/// 3) update the Hardware for any testobjects to the new hardware and away from whatever they had
///
/// this is being done for
/// 12496 Discover Hardware in test setup should refresh or "update items" automatically
/// where the incoming hardwareToRemove may be updated configurations
/// </summary>
/// <param name="hardwareToRemove"></param>
public void RemoveCachedHardware(DASHardware[] hardwareToRemove)
{
var dictionary = hardwareToRemove.ToDictionary(h => h.SerialNumber);
//since groups have their own pointers to hardware
//we have to make sure they aren't point to old hardware records
//that way if someone accesses the hardware via the group, they have an updated copy
foreach (var group in TestObjects)
{
var list = group.Hardware.ToList();
for (var i = list.Count - 1; i >= 0; i--)
{
if (dictionary.ContainsKey(list[i].SerialNumber))
{
list[i] = dictionary[list[i].SerialNumber];
}
}
group.SetHardware(list.ToArray());
}
foreach (var group in AddedGroups)
{
var list = group.Hardware.ToList();
for (var i = list.Count - 1; i >= 0; i--)
{
if (dictionary.ContainsKey(list[i].SerialNumber))
{
list[i] = dictionary[list[i].SerialNumber];
}
}
group.SetHardware(list.ToArray());
}
}
public DASHardware GetCachedHardware(string serialNumber)
{
return null;
}
/// <summary>
/// All items from db are updated in our cache
/// </summary>
public void UpdateFromDb()
{
ClearHardware();
DASHardwareList.GetList().ClearCache();
DASHardwareList.GetList().ReloadAll();
SensorCalibrationList.ClearCachedCalibrations();
SensorCalibrationList.Reload();
SensorsCollection.SensorsList.ClearCache();
SensorsCollection.SensorsList.Reload();
foreach (var group in Groups)
{
group.ClearGroupChannelSettingCache(group.Id);
}
TestTemplateList.TestTemplatesList.CachedCustomerDetails = null;
TestTemplateList.TestTemplatesList.CachedLaboratoryDetails = null;
TestTemplateList.TestTemplatesList.CachedTestEngineerDetails = null;
Groups.Clear();
ChannelsForGroup.Clear();
LoadFromDb();
}
public IDASHardware[] GetHardwareFromDb()
{
var includedIds = AddedHardware;
var list = new List<IDASHardware>();
var lookup = DASHardwareList.GetAllHardware().ToDictionary(d => d.DASId);
foreach (var id in includedIds)
{
if (lookup.ContainsKey(id))
{
list.Add(lookup[id]);
}
}
foreach (var id in RemovedHardware)
{
if (lookup.ContainsKey(id))
{
list.Add(lookup[id]);
}
}
return list.ToArray();
}
public IDASHardware[] GetAllCachedHardware2()
{
return new IDASHardware[0];
}
public ISensorCalibration[] GetCachedSensorCalibrations()
{
return new ISensorCalibration[0];
}
public SensorCalibration[] GetCachedSensorCalibrations2()
{
return new SensorCalibration[0];
}
public ISensorData[] GetCachedSensors()
{
return new ISensorData[0];
}
//FB 18875 Populate Cached Sensors
public SensorData[] GetCachedSensors2()
{
return GetAllSensorsFromDB();
}
public SensorData[] GetOriginalCachedSensors()
{
return new SensorData[0];
}
public SensorData GetCachedSensor(string serialNumber)
{
return null;
}
public SensorCalibration[] GetCalibrations(string serialNumber)
{
return null;
}
//FB 18875 Get all sesnors from database which can be used in cache
/// <summary>
/// Get all sensors from database
/// </summary>
/// <returns>SensorData list</returns>
public SensorData[] GetAllSensorsFromDB()
{
var sensors = new List<SensorData>();
var cals = SensorsCollection.GetLatestCalibrations();
var hr = DbOperations.SensorsAnalogGet(null, null, null, out var records);
if (0 == hr && null != records && records.Any())
{
foreach (var record in records)
{
var sd = new SensorData(record, cals);
sensors.Add(sd);
}
}
hr = DbOperations.SensorsDigitalInGet(null, null, null, out var digitalIns);
if (0 == hr && null != digitalIns && digitalIns.Any())
{
foreach (var digitalIn in digitalIns)
{
sensors.Add(new DigitalInputSetting(digitalIn));
}
}
hr = DbOperations.SensorsSquibGet(null, null, null, out var squibrecords);
if (0 == hr && null != squibrecords && squibrecords.Any())
{
foreach (var record in squibrecords)
{
var squib = new SquibSetting(record);
sensors.Add(squib);
}
}
hr = DbOperations.SensorsUARTGet(null, null, out var uartRecords);
if (0 == hr && null != uartRecords && uartRecords.Any())
{
foreach (var uartRecord in uartRecords)
{
var uart = new UartSetting(uartRecord);
sensors.Add(uart);
}
}
hr = DbOperations.SensorsStreamOutputGet(null, null, out var outputRecords);
if (0 == hr && null != outputRecords && outputRecords.Any())
{
foreach (var record in outputRecords)
{
sensors.Add(new StreamOutputSetting(record));
}
}
return sensors.ToArray();
}
//added to prevent a bad binding expecting this property to be present
public System.Windows.Media.Brush Background => System.Windows.Media.Brushes.Transparent;
public void InitializeFrom(TestTemplate source)
{
OldTestTemplateLiteCopy(source);
AddedGroups = source.AddedGroups;
AllowMissingSensors = source.AllowMissingSensors;
AllowSensorIdToBlankChannel = source.AllowSensorIdToBlankChannel;
ArmCheckListStep = source.ArmCheckListStep;
AutomaticProgression = source.AutomaticProgression;
AutomaticProgressionDelayMS = source.AutomaticProgressionDelayMS;
AutoVerifyChannels = source.AutoVerifyChannels;
AutoVerifyDelaySeconds = source.AutoVerifyDelaySeconds;
CalibrationBehavior = source.CalibrationBehavior;
CheckedDASList = source.CheckedDASList;
CheckListBatteryVoltageCheck = source.CheckListBatteryVoltageCheck;
CheckListInputVoltageCheck = source.CheckListInputVoltageCheck;
CheckListRequirePass = source.CheckListRequirePass;
CheckListSensorIdCheck = source.CheckListSensorIdCheck;
CheckListSquibResistanceCheck = source.CheckListSquibResistanceCheck;
CheckListTemperatureCheck = source.CheckListTemperatureCheck;
CheckListTiltSensorCheck = source.CheckListTiltSensorCheck;
CheckListTriggerStartCheck = source.CheckListTriggerStartCheck;
CheckoutMode = source.CheckoutMode;
CommonLine = source.CommonLine;
CustomerDetails = source.CustomerDetails;
DASSettings = source.DASSettings;
DefaultNumberRealtimeGraphs = source.DefaultNumberRealtimeGraphs;
Description = source.Description;
DoAutoArm = source.DoAutoArm;
DoEnableRepeat = source.DoEnableRepeat;
DoStreaming = source.DoStreaming;
DoROIDownload = source.DoROIDownload;
DownloadAll = source.DownloadAll;
DownloadFolder = source.DownloadFolder;
ExcitationWarmup = source.ExcitationWarmup;
ExportFolder = source.ExportFolder;
ExportFormats = source.ExportFormats;
ExpressTestSetup = source.ExpressTestSetup;
FilterLookup = source.FilterLookup;
GroupsStepValid = source.GroupsStepValid;
InvertStartRecordCompletion = source.InvertStartRecordCompletion;
InvertTriggerCompletion = source.InvertTriggerCompletion;
IgnoreShortedStartCompletion = source.IgnoreShortedStartCompletion;
IgnoreShortedTriggerCompletion = source.IgnoreShortedTriggerCompletion;
base.IsComplete = source.GetIsCompleteNoFunctions();
IsDirty = source.IsDirty;
ISFFile = source.ISFFile;
LabDetails = source.LabDetails;
LastModified = source.LastModified;
LastModifiedBy = source.LastModifiedBy;
LevelTriggerChannels = source.LevelTriggerChannels;
LocalOnly = source.LocalOnly;
Name = source.Name;
NotAllChannelsRealTime = source.NotAllChannelsRealTime;
NotAllChannelsViewer = source.NotAllChannelsViewer;
OriginalTestDirectory = source.OriginalTestDirectory;
OtherAddedGroups = source.OtherAddedGroups;
PostTestDiagnosticsLevel = source.PostTestDiagnosticsLevel;
PostTriggerSeconds = source.PostTriggerSeconds;
PreserveTestId = source.PreserveTestId;
PreTriggerSeconds = source.PreTriggerSeconds;
QuickSensorCheck = source.QuickSensorCheck;
QuitTestWithoutWarning = source.QuitTestWithoutWarning;
RecordingMode = source.RecordingMode;
NumberOfEvents = source.NumberOfEvents;
WakeUpMotionTimeout = source.WakeUpMotionTimeout;
RequireUserConfirmationOnErrors = source.RequireUserConfirmationOnErrors;
ROIEnd = source.ROIEnd;
ROIStart = source.ROIStart;
SameAsDownloadFolder = source.SameAsDownloadFolder;
SamplesPerSecondAggregate = source.SamplesPerSecondAggregate;
SetupFile = source.SetupFile;
StrictDiagnostics = source.StrictDiagnostics;
SuppressMissingSensorsWarning = source.SuppressMissingSensorsWarning;
TagIDs = source.TagIDs;
TestDirectory = source.TestDirectory;
TestEngineerDetails = source.TestEngineerDetails;
TestGraphs = source.TestGraphs.Select(tg => new TestGraph(tg)).ToArray(); //use same method as new(copy)
_id = source._id;
TestIdNode = source.TestIdNode;
_testObjects = source._testObjects;
TestObjectsAndAddedGroupsList = source.TestObjectsAndAddedGroupsList;
_groups = source._groups;
Groups = source.Groups;
ChannelsForGroup = source.ChannelsForGroup;
_metaDataLookup?.Clear();
SetMetaData(source._metaDataLookup?.Values?.ToArray());
_testSetupMeta?.Clear();
SetTestSetupMetaData(source._testSetupMeta);
TestTime = source.TestTime;
TriggerCheckRealtime = source.TriggerCheckRealtime;
TriggerCheckStep = source.TriggerCheckStep;
TurnOffExcitation = source.TurnOffExcitation;
UploadData = source.UploadData;
UploadFolder = source.UploadFolder;
VerifyChannels = source.VerifyChannels;
ViewDiagnostics = source.ViewDiagnostics;
ViewDownloadAll = source.ViewDownloadAll;
ViewExport = source.ViewExport;
_viewRealtime = source._viewRealtime;
ViewROIDownload = source.ViewROIDownload;
WarnOnFailedBattery = source.WarnOnFailedBattery;
ClockSyncProfileMaster = source.ClockSyncProfileMaster;
ClockSyncProfileSlave = source.ClockSyncProfileSlave;
CalculatedChannels.Clear();
CalculatedChannels.AddRange(source.CalculatedChannels);
MeasureSquibResistancesStep = source.MeasureSquibResistancesStep;
HardwareOverrides.Clear();
using (var enumHardware = source.HardwareOverrides.GetEnumerator())
{
while (enumHardware.MoveNext())
{
HardwareOverrides[enumHardware.Current.Key] =
new HardwareInclusionInstruction(enumHardware.Current.Value);
}
}
}
/// <summary>
/// loads all the information for the test setup from tables in the db
/// we do this so that we can keep the minimal information on hand until we need it
/// </summary>
public void LoadFromDb()
{
DASSamplesPerPacketUpToDate = false; //Don't check until it's been set (and not to the default)
if (QuickSensorCheck) { return; }
if (string.IsNullOrWhiteSpace(Name)) { return; } //nothing to load!
var tblMetaData = new Dictionary<string, List<Dictionary<string, object>>>(100);
#region Load Groups
var groupIds = new List<int>();
var unityContainer = ContainerLocator.Container.Resolve<IUnityContainer>();
//IGroupListViewModel vm = null;
if (null == _vm)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
_vm = unityContainer.Resolve<IGroupListViewModel>();
manualResetEvent.Set();
}));
manualResetEvent.WaitOne();
}
else
{
_vm = unityContainer.Resolve<IGroupListViewModel>();
}
}
var groupIdToDisplayOrder = new Dictionary<int, int>();
var groupIdToPosition = new Dictionary<int, string>();
var groupIdToTestObject = new Dictionary<int, string>();
var hr = DbOperations.TestSetupGroupsGet(null, null, Name, out var records);
if (0 == hr && null != records && records.Any())
{
foreach (var record in records)
{
groupIdToDisplayOrder[record.GroupId] = record.DisplayOrder;
groupIdToPosition[record.GroupId] = record.Position;
groupIdToTestObject[record.GroupId] = record.TestObjectType;
groupIds.Add(record.GroupId);
}
}
var sensorLookup = new Dictionary<int, ISensorData>();
var sensors = SensorsCollection.SensorsList.GetAllSensors(false);
foreach (var s in sensors)
{
sensorLookup[s.DatabaseId] = s;
}
var hardwareLookup = new Dictionary<int, IDASHardware>();
var hardware = DASHardwareList.GetAllHardware();
foreach (var h in hardware)
{
hardwareLookup[h.DASId] = h;
}
//Update the Tags in case they were modified by a different user
DTS.Common.Classes.Tags.TagsInstance.GetTagsInstance(DbOperations.TagsGet).UpdateList(DbOperations.TagsGet);
var groups = new List<IGroup>();
foreach (var id in groupIds)
{
//We don't need to update the Tags since it was just done above
var group = _vm.GetGroup(id, false);
group.DisplayOrder = groupIdToDisplayOrder[id];
group.LoadHardware();
groups.Add(group);
}
groups.Sort();
var channelDefaults = DbOperations.GetChannelSettingDefaults();
foreach (var group in groups)
{
AddGroup(group, sensorLookup, hardwareLookup, channelDefaults);
}
//Get the TestSetupHardware table
//FB 23926 Refactor
var testSetupHardwareGetWrapper = new TestSetupHardwareGet();
var testSetupHardwareGetList = testSetupHardwareGetWrapper.TestSetupHardwareGet_Wrapper(Id, hardwareLookup);
var added = new List<int>();
var removed = new List<int>();
foreach (var testSetupHardwareGet in testSetupHardwareGetList)
{
DASSampleRateList[hardwareLookup[testSetupHardwareGet.DASId].SerialNumber] = testSetupHardwareGet.SamplesPerSecond;
DASClockMasterList[hardwareLookup[testSetupHardwareGet.DASId].SerialNumber] = testSetupHardwareGet.IsClockMaster &&
testSetupHardwareGet.AddOrRemove;
DASAAFRateList[hardwareLookup[testSetupHardwareGet.DASId].SerialNumber] = testSetupHardwareGet.AntiAliasFilterRate;
DASSamplesPerPacketList[hardwareLookup[testSetupHardwareGet.DASId].SerialNumber] = GetSamplesPerPacketForHardware(testSetupHardwareGet.SamplesPerSecond);
DASSamplesPerPacketUpToDate = true; //The dictionary has been changed, so we want to validate.
DASPTPDomainIDList[hardwareLookup[testSetupHardwareGet.DASId].SerialNumber] = testSetupHardwareGet.PTPDomainId;
if (testSetupHardwareGet.AddOrRemove)
{
added.Add(testSetupHardwareGet.DASId);
}
else
{
removed.Add(testSetupHardwareGet.DASId);
}
}
AddedHardware = added.ToArray();
RemovedHardware = removed.ToArray();
var defaultRate = TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id).DefaultTestSampleRate;
//Add the default sample rate for any DAS that's not included in the test in case it gets included the test later
foreach (var h in hardware)
{
if (!DASSampleRateList.ContainsKey(h.SerialNumber))
{
DASSampleRateList[h.SerialNumber] = defaultRate;
}
}
#endregion Load Groups
#region Load Meta Data
try
{
using (var cmd = DbOperations.GetSQLCommand(true))
{
try
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_TestSetupObjectMetaDataGet.ToString();
cmd.Parameters.Add(new SqlParameter("@TestSetupName", SqlDbType.NVarChar, 50) { Value = Name });
IDataReader reader = cmd.ExecuteReader();
TestTemplateList.ConvertToDictionary(reader, ref tblMetaData,
DbOperations.TestSetups.TestObjectMetaDataFields.TestSetupName.ToString());
}
finally
{
cmd.Connection.Dispose();
}
}
}
catch (Exception ex) { APILogger.Log(ex); }
#endregion Meta Data
#region Load Level Triggers
LevelTriggerChannels.Clear();
var levelTriggerChannels = new List<LevelTriggerChannel>();
try
{
using (var cmd = DbOperations.GetSQLCommand(true))
{
try
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_LevelTriggersGet.ToString();
cmd.Parameters.Add(
new SqlParameter("@Id", SqlDbType.Int) { Value = DBNull.Value });
cmd.Parameters.Add(
new SqlParameter("@ChannelId", SqlDbType.Int) { Value = DBNull.Value });
cmd.Parameters.Add(
new SqlParameter("@TestSetupId", SqlDbType.Int) { Value = DBNull.Value });
cmd.Parameters.Add(new SqlParameter("@TestSetupName", SqlDbType.NVarChar) { Value = Name });
using (var ds = DbOperations.Connection.QueryDataSet(cmd))
{
foreach (DataRow row in ds.Tables[0].Rows)
{
try
{
levelTriggerChannels.Add(new LevelTriggerChannel(row));
}
catch (Exception ex2)
{
APILogger.Log(ex2);
}
}
}
}
finally { cmd.Connection.Dispose(); }
}
}
catch (Exception ex) { APILogger.Log(ex); }
#endregion
ProcessMetaData(tblMetaData);
_bIsLoaded = true;
#region Process Level Triggers
foreach (var lt in levelTriggerChannels)
{
SetLevelTrigger(lt);
}
#endregion Process Level Triggers
#region Graphs
LoadGraphsFromDb();
#endregion Graphs
#region CC
LoadCalculatedChannelsFromDb();
#endregion CC
#region ROI
// If we're using a db with the (new) TestSetupROIs and ROIPeriodChannels tables, we need
// to use them to build the RegionsOfInterest. If not, the RegionsOfInterest was built
// from the string RegionsOfInterest field in the (old) TestSetups table.
var dbVersion = DbOperations.GetConnectionDbVersion();
if (dbVersion >= DTS.Common.Constants.ROITables_DB_VERSION)
{
LoadRegionsOfInterestFromDb();
}
else
{
// We're using an old db, so add the hardware channel assignments if possible, similar
// to how we do it in MigrateVersion91();
AddHardwareToROIChannelNames();
}
if (dbVersion < Constants.ROIPERIODCHANNELS_CHANNELID_DB_VERSION)
{
AddROIChannelIds();
SqlCommand cmd = DbOperations.GetSQLCommand(true);
var roiList = DbOperations.MigrateChannelNamesToChannelIds(cmd, Id, false);
//Assign channelIds to the ROIs so the ROI x Channels step works correctly
var roiIndex = 0;
foreach (var roi in roiList)
{
foreach (var idNamePair in roi)
{
var channelNameIndex = 0;
var found = false;
while (!found && channelNameIndex < (RegionsOfInterest[roiIndex].ChannelNames.Length))
{
if (RegionsOfInterest[roiIndex].ChannelNames[channelNameIndex] == idNamePair.Value)
{
RegionsOfInterest[roiIndex].ChannelIds[channelNameIndex] = idNamePair.Key;
found = true;
}
channelNameIndex++;
}
}
roiIndex++;
}
}
if (dbVersion < Constants.EnableRepeat_DB_VERSION)
{
// The old db doesn't have the Enable Repeat value in
// the TestSetups table, so get it from the System Settings.
var settings = TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id);
DoEnableRepeat = settings.DefaultAutoArmRepeatEnable;
}
#endregion ROI
}
/// <summary>
/// I abstracted this code out of LoadFromDB, it's just the code that was handling the iso meta data
/// </summary>
/// <param name="tblMetaData"></param>
private void ProcessMetaData(IReadOnlyDictionary<string, List<Dictionary<string, object>>> tblMetaData)
{
var metas = new Dictionary<char, TestObjectMetaData>();
var setupMeta = new TestSetupMetaData(DataModelSettings.RequireXCrashCompatibilityForISOExports);
if (tblMetaData.ContainsKey(Name))
{
//Don't rely on LabName, CustName, or TEName being processed before their associated fields
//so run through the table to ensure these are analyzed before the associated fields are processed.
var useLabDetails = false;
var useCustomerDetails = false;
var useTestEngineerDetails = false;
foreach (var row in tblMetaData[Name])
{
var pname = Convert.ToString(row[DbOperations.TestSetups.TestObjectMetaDataFields.PropName.ToString()]);
var pvalue = Convert.ToString(row[DbOperations.TestSetups.TestObjectMetaDataFields.PropValue.ToString()]);
var to = GetTestObject(row);
if (to.Equals(Constants.ISOTestInfo))
{
//Only use xDetails if they are in the Test Setup AND there is not a legitimate entry in the
//TestSetupObjectMetaDatatable (value is "NOVALUE"). Otherwise, use what's in the table.
switch (pname)
{
case "LabName":
useLabDetails = (LabDetails != null) && (pvalue == "NOVALUE");
break;
case "CustName":
useCustomerDetails = (CustomerDetails != null) && (pvalue == "NOVALUE");
break;
case "TEName":
useTestEngineerDetails = (TestEngineerDetails != null) && (pvalue == "NOVALUE");
break;
}
}
}
foreach (var row in tblMetaData[Name])
{
var bOptional = Convert.ToBoolean(row[DbOperations.TestSetups.TestObjectMetaDataFields.Optional.ToString()]);
var pname = Convert.ToString(row[DbOperations.TestSetups.TestObjectMetaDataFields.PropName.ToString()]);
var pvalue = Convert.ToString(row[DbOperations.TestSetups.TestObjectMetaDataFields.PropValue.ToString()]);
var to = GetTestObject(row);
//little wonky here, sometimes the character comes in as a number, sometimes as a string.
//if we end up with a string longer than 1 character, then we definitely need to convert it.
//there are no strings of length 2 that are a valid character
if (to.Length > 1)
{
try
{
if (int.TryParse(to, out int iTemp)) { to = Convert.ToString(Convert.ToChar(iTemp)); }
}
catch (Exception ex) { APILogger.Log(ex); }
}
var version = Convert.ToDouble(row[DbOperations.TestSetups.TestObjectMetaDataFields.Version.ToString()]);
if (to.Equals(Constants.ISOTestInfo))
{
if ((pname == "Title") && ((pvalue == "NOVALUE") || (string.IsNullOrWhiteSpace(pvalue))))
{
pvalue = Name;
}
else if (pname == "DateOfTheTest")
{
pvalue = DateTime.Now.ToString("yyyy-MM-dd");
}
//31883 Databases that are migrated from 3.3 or earlier may have empty strings in the
//TestSetupObjectMetaData table, so use what's in the Laboratory/Customer/TestEngineerDetails
//if there is a Laboratory/Customer/TestEngineer associated with the Test Setup.
//Additionally, if there are non-empty values, they are from saving a Test Setup after modifying (overrides).
switch (pname)
{
case "LabName":
pvalue = GetMetaDataPValue(useLabDetails, pvalue, LabDetails?.Name);
break;
case "LaboratoryContactName":
pvalue = GetMetaDataPValue(useLabDetails, pvalue, LabDetails?.LabratoryContactName);
break;
case "LaboratoryContactPhone":
pvalue = GetMetaDataPValue(useLabDetails, pvalue, LabDetails?.LabratoryContactPhone);
break;
case "LaboratoryContactFax":
pvalue = GetMetaDataPValue(useLabDetails, pvalue, LabDetails?.LabratoryContactFax);
break;
case "LaboratoryContactEmail":
pvalue = GetMetaDataPValue(useLabDetails, pvalue, LabDetails?.LabratoryContactEmail);
break;
case "LaboratoryName":
pvalue = GetMetaDataPValue(useLabDetails, pvalue, LabDetails?.LabratoryName);
break;
case "LaboratoryTestReferenceNumber":
pvalue = GetMetaDataPValue(useLabDetails, pvalue, LabDetails?.LabratoryTestRefNumber);
break;
case "LaboratoryProjectReferenceNumber":
pvalue = GetMetaDataPValue(useLabDetails, pvalue, LabDetails?.LabratoryProjectRefNumber);
break;
case "CustName":
pvalue = GetMetaDataPValue(useCustomerDetails, pvalue, CustomerDetails?.Name);
break;
case "CustomerName":
pvalue = GetMetaDataPValue(useCustomerDetails, pvalue, CustomerDetails?.CustomerName);
break;
case "CustomerTestReferenceNumber":
pvalue = GetMetaDataPValue(useCustomerDetails, pvalue, CustomerDetails?.CustomerTestRefNumber);
break;
case "CustomerProjectReferenceNumber":
pvalue = GetMetaDataPValue(useCustomerDetails, pvalue, CustomerDetails?.ProjectRefNumber);
break;
case "CustomerOrderNumber":
pvalue = GetMetaDataPValue(useCustomerDetails, pvalue, CustomerDetails?.CustomerOrderNumber);
break;
case "CustomerCostUnit":
pvalue = GetMetaDataPValue(useCustomerDetails, pvalue, CustomerDetails?.CustomerCostUnit);
break;
case "TEName":
pvalue = GetMetaDataPValue(useTestEngineerDetails, pvalue, TestEngineerDetails?.Name);
break;
case "TestEngineerName":
pvalue = GetMetaDataPValue(useTestEngineerDetails, pvalue, TestEngineerDetails?.TestEngineerName);
break;
case "TestEngineerPhone":
pvalue = GetMetaDataPValue(useTestEngineerDetails, pvalue, TestEngineerDetails?.TestEngineerPhone);
break;
case "TestEngineerFax":
pvalue = GetMetaDataPValue(useTestEngineerDetails, pvalue, TestEngineerDetails?.TestEngineerFax);
break;
case "TestEngineerEmail":
pvalue = GetMetaDataPValue(useTestEngineerDetails, pvalue, TestEngineerDetails?.TestEngineerEmail);
break;
}
setupMeta.SetProperty(new MetaData(pname, bOptional, pvalue, version), DataModelSettings.RequireXCrashCompatibilityForISOExports);
}
else
{
if (!metas.ContainsKey(to[0])) { metas.Add(to[0], new TestObjectMetaData(to[0])); }
metas[to[0]].SetProperty(new MetaData(pname, bOptional, pvalue, version));
}
}
}
foreach (var v in metas.Values)
{
SetMetaData(v.TestObject, v);
}
SetTestSetupMetaData(setupMeta);
}
/// <summary>
/// returns iso meta data property value given some conditions
/// I abstracted this code out of existing code, so I can't fully validate what it was tryign to do
/// but I think the idea was if you are using an iso property then get the value from the global reference for that customer/
/// testengineer/lab
/// but I modified it to also consider whether there was an override value or not
/// http://manuscript.dts.local/f/cases/44545/Setting-test-meta-data-only-doesn-t-save-in-DP-4-2
/// </summary>
/// <param name="getValue"></param>
/// <param name="overrideValue"></param>
/// <param name="fieldValue"></param>
/// <returns></returns>
private static string GetMetaDataPValue(bool getValue, string overrideValue, string fieldValue)
{
if (!getValue) { return overrideValue; }
if (string.IsNullOrWhiteSpace(overrideValue) || TestObjectMetaData.NOVALUE.Equals(overrideValue))
{
return fieldValue ?? TestObjectMetaData.NOVALUE;
}
return overrideValue;
}
/// <summary>
/// returns the Test Object portion of an ISOcode
/// </summary>
/// <param name="row"></param>
/// <returns></returns>
private string GetTestObject(Dictionary<string, object> row)
{
var to = "?";
try
{
if (row[DbOperations.TestSetups.TestObjectMetaDataFields.ISOTestObject.ToString()] is string)
{
to = row[DbOperations.TestSetups.TestObjectMetaDataFields.ISOTestObject.ToString()] as string;
}
else
{
to = Convert.ToString(Convert.ToChar(Convert.ToInt32(row[DbOperations.TestSetups.TestObjectMetaDataFields.ISOTestObject.ToString()])));
}
}
catch (Exception ex) { APILogger.Log(ex); }
return to;
}
/// <summary>
/// Prepends the hardware assignment, if possible, to the channel name to form,
/// for example, "[S6A12345] CH-02\\ARS9003". If the channel has
/// not been assigned to hardware, or if there are more than one with the same sensor, then
/// the hardware will not be added.
/// </summary>
private void AddHardwareToROIChannelNames()
{
var regionsOfInterest = RegionsOfInterest;
foreach (var regionOfInterest in regionsOfInterest)
{
var channelNames = regionOfInterest.ChannelNames;
var channelNameIndex = 0;
foreach (var channelName in channelNames)
{
//Find the channel's hardware channel if is assigned and can be determined.
var newChannelName = channelName;
var found = false;
foreach (var groupOfChannels in ChannelsForGroup)
{
foreach (var channel in groupOfChannels.Value)
{
if (channel.Sensor == channelName)
{
if (channel.Hardware != null && channel.Hardware != "")
{
if (found)
{
//Uh oh, we found more than one with this sensor, so we can't
//prepend the ChannelName with the Hardware
newChannelName = channelName;
}
else
{
if (channel.SensorData.SerialNumber == SensorConstants.TEST_SPECIFIC_ANALOG_SERIAL)
{
newChannelName = GenerateEmbeddedChannelName(channel.Hardware.Substring(0, channel.Hardware.IndexOf('-')), $"\\{channelName}");
}
else
{
newChannelName = $"{channel.Hardware}\\{channelName}";
}
found = true;
}
}
}
}
}
regionOfInterest.ChannelNames[channelNameIndex] = newChannelName;
channelNameIndex++;
}
}
RegionsOfInterest = regionsOfInterest;
}
private void AddROIChannelIds()
{
var regionsOfInterest = RegionsOfInterest;
foreach (var regionOfInterest in regionsOfInterest)
{
var channelNames = regionOfInterest.ChannelNames;
var channelNameIndex = 0;
foreach (var channelName in channelNames)
{
//Find the channel's id
Int64 channelId = -1;
var found = false;
foreach (var groupOfChannels in ChannelsForGroup)
{
foreach (var channel in groupOfChannels.Value)
{
if (!found) //Don't stomp on an Id that we found
{
channelId = -1;
}
var possibleHardware = string.Empty;
var possibleChannelNumber = string.Empty;
if (string.IsNullOrWhiteSpace(channel.Hardware) || channel.Hardware.StartsWith("Assigned")) continue;
possibleHardware = $"[{channel.HardwareChannel.ModuleSerialNumber}]";
possibleChannelNumber = channel.Hardware.Substring(channel.Hardware.LastIndexOf('-') + 1, 2);
var possibleMatch = $"{possibleHardware} CH-{possibleChannelNumber}\\{channel.GetChannelName(SerializedSettings.ISOViewMode)}";
if (possibleMatch == channelName)
{
if (found)
{
//Uh oh, we found more than one with this sensor, so we can't
channelId = -1;
}
else
{
channelId = channel.Id;
found = true;
}
}
}
}
regionOfInterest.ChannelIds[channelNameIndex] = channelId;
channelNameIndex++;
}
}
RegionsOfInterest = regionsOfInterest;
}
private void LoadCalculatedChannelsFromDb()
{
CalculatedChannels.Clear();
var hr = DbOperations.CalculatedChannelsGet(null, Name, out var records);
var calculatedChannels = new List<CalculatedValueClass>();
if (0 == hr && null != records && records.Any())
{
foreach (var record in records)
{
calculatedChannels.Add(new CalculatedValueClass(record));
}
}
CalculatedChannels = calculatedChannels;
}
private void LoadRegionsOfInterestFromDb()
{
var hresult = DbOperations.RegionsOfInterestGet(Id, out var records);
var regionsOfInterest = new BindingList<IRegionOfInterest>();
if (0 == hresult && null != records && records.Any())
{
foreach (var record in records)
{
var newRecord = AddHardwareToChannelsIfNeeded(record, Id);
regionsOfInterest.Add(newRecord);
}
}
RegionsOfInterest = regionsOfInterest;
}
/// <summary>
/// If a version 91 client created a Test Setup with multiple ROIs, the hardware
/// associated with the channels in the RegionsOfInterest record will not have
/// been prepended to the values in the ChannelNames array.
/// So, prepend the hardware if possible here.
/// This code is similar to that in the database migration.
///
/// Additionally, if a version 92 client created a Test Setup with multiple ROIs, but
/// with no hardware assigned, the channel names will be preceded with "\\".
/// </summary>
/// <param name="record"></param>
/// <param name="testSetupId"></param>
/// <returns></returns>
private IRegionOfInterest AddHardwareToChannelsIfNeeded(IRegionOfInterest record, int testSetupId)
{
IRegionOfInterest newRecord = record;
var index = 0;
foreach (var channelName in record.ChannelNames)
{
var plainChannelName = channelName.TrimStart();
// Strip off Assigned by ID
if (channelName.StartsWith(DTS.Common.Strings.Strings.AssignedByID))
{
plainChannelName = channelName.Substring(channelName.IndexOf('\\') + 1).TrimStart();
}
if (!plainChannelName.StartsWith("["))
{
//Find the channel's hardware channel if it is assigned and can be determined.
if (channelName.StartsWith("\\"))
{
plainChannelName = channelName.Substring(1);
}
var newChannelName = $"\\{plainChannelName}";
//Get all of the GroupId values from the TestSetupGroups table with this TestSetupId
var groupIdList = GetGroupIds(testSetupId);
if (groupIdList.Any())
{
//Get the id from the Sensors table
var tsrAirChannelFound = false;
var sensorIdAndTypeDict = GetSensorId(plainChannelName);
if (!sensorIdAndTypeDict.Any() && channelName == SensorConstants.TEST_SPECIFIC_ANALOG_SERIAL)
{
//None returned, so see if this is a TSR AIR channel
sensorIdAndTypeDict = GetSensorId(SensorConstants.TEST_SPECIFIC_ANALOG_SERIAL);
tsrAirChannelFound = sensorIdAndTypeDict.Any();
}
//If more than one row returned give up
if (sensorIdAndTypeDict.Count == 1)
{
//Get all of the DASIds and DASChannelIndex values from the Channels table with the GroupId and SensorId
foreach (var groupId in groupIdList)
{
var dasIdAndDasChannelIndexList = GetDASIdAndDASChannelIndex(groupId, sensorIdAndTypeDict.FirstOrDefault().Key);
if (tsrAirChannelFound)
{
var serialNumber = GetDASSerialNumber(dasIdAndDasChannelIndexList[0].Item1);
newChannelName = GenerateEmbeddedChannelName(serialNumber, $"\\{plainChannelName}");
}
else
{
//If more than one row returned, give up
if (dasIdAndDasChannelIndexList.Count == 1)
{
// Get the SerialNumber and ParentDAS from the DAS table and combine with DASChannelIndex from Channels table
// and the channelName before storing ([SPE00596:SPS01235] CH-04\\an1)
var serialNumber = GetDASSerialNumber(dasIdAndDasChannelIndexList[0].Item1);
if (serialNumber != "")
{
var indexOfColon = serialNumber.IndexOf(":");
if (indexOfColon > -1)
{
//Remove the left side of the colon when the format is SPE12345:SPS54321
serialNumber = serialNumber.Substring(indexOfColon + 1);
}
newChannelName = BuildChannelName(serialNumber, sensorIdAndTypeDict.FirstOrDefault().Value == 3,
dasIdAndDasChannelIndexList[0].Item2, plainChannelName);
}
}
}
}
}
}
newRecord.ChannelNames[index] = newChannelName;
}
index++;
}
return newRecord;
}
/// <summary>
/// used to add hardware when importing a pre-4.0 Test Setup export with multiple ROIs
/// </summary>
/// <param name="channelName"></param>
/// <param name="sensorLookup"></param>
/// <param name="hardware"></param>
/// <returns></returns>
string AddHardwareToImportedChannelIfAssigned(string channelName, Dictionary<string, SensorData> sensorLookup, List<DASHardware> hardware)
{
var newChannelName = $"\\{channelName}";
var sensorId = sensorLookup[channelName].Id;
foreach (var group in ChannelsForGroup)
{
foreach (var channel in group.Value)
{
if (channel.SensorId == sensorId)
{
var dasId = channel.DASId;
if (dasId != -1)
{
foreach (var hw in hardware)
{
if (hw.DASId == dasId)
{
newChannelName = BuildChannelName(hw.SerialNumber, sensorLookup[channelName].Bridge == SensorConstants.BridgeType.SQUIB,
channel.DASChannelIndex, channelName);
break;
}
}
}
break;
}
}
}
return newChannelName;
}
/// <summary>
/// builds a channel name with hardware when hardware is assigned to multiple ROI channels
/// </summary>
/// <param name="dasSerialNumber"></param>
/// <param name="sensorIsSquib"></param>
/// <param name="dasChannelIndex"></param>
/// <param name="channelName"></param>
/// <returns></returns>
string BuildChannelName(string dasSerialNumber, bool sensorIsSquib, int dasChannelIndex, string channelName)
{
var sensorLabel = "CH";
var dasChannelNumber = dasChannelIndex + 1;
if (sensorIsSquib)
{
sensorLabel = "SQ";
dasChannelNumber = ((dasChannelIndex / 2) + 1);
}
var newChannelName = $"[{dasSerialNumber}] {sensorLabel}-{dasChannelNumber.ToString("00")}\\{channelName}";
return newChannelName;
}
/// <summary>
/// This function takes a TSR AIR serial number and a channel name that doesn't have
/// hardware pre-pended, and returns a new channel name with the hardware pre-pended.
/// </summary>
/// <param name="serialNumber"></param>
/// <param name="channelName"></param>
/// <returns></returns>
public string GenerateEmbeddedChannelName(string serialNumber, string channelName)
{
var newChannelName = string.Empty;
var channelNumber = 0;
if (channelName.Contains(DFConstantsAndEnums.LOWG_SERIAL_APPEND))
{
serialNumber = $"{serialNumber}{SensorConstants.LowG}";
channelNumber = Convert.ToInt32(channelName.Substring(channelName.Length - 1, 1));
}
else if (channelName.Contains(DFConstantsAndEnums.HIGHG_SERIAL_APPEND))
{
serialNumber = $"{serialNumber}{SensorConstants.HighG}";
channelNumber = Convert.ToInt32(channelName.Substring(channelName.Length - 1, 1));
}
else if (channelName.Contains(DFConstantsAndEnums.USER_CHANNEL_NAME_ANGULAR_RATE))
{
serialNumber = $"{serialNumber}{SensorConstants.ARS}";
channelNumber = Convert.ToInt32(channelName.Substring(channelName.Length - 1, 1));
}
else if (channelName.Contains(DFConstantsAndEnums.USER_CHANNEL_NAME_TEMPERATURE) ||
channelName.Contains(DFConstantsAndEnums.USER_CHANNEL_NAME_HUMIDITY) ||
channelName.Contains(DFConstantsAndEnums.USER_CHANNEL_NAME_PRESSURE))
{
serialNumber = $"{serialNumber}{SensorConstants.Atm}";
if (channelName.Contains(DFConstantsAndEnums.USER_CHANNEL_NAME_TEMPERATURE))
{
channelNumber = 1;
}
else if (channelName.Contains(DFConstantsAndEnums.USER_CHANNEL_NAME_HUMIDITY))
{
channelNumber = 2;
}
else if (channelName.Contains(DFConstantsAndEnums.USER_CHANNEL_NAME_PRESSURE))
{
channelNumber = 3;
}
}
newChannelName = $"[{serialNumber}] {StringResources.ChannelPrefix_Other}{(channelNumber).ToString("00")}{channelName}";
return newChannelName;
}
/// <summary>
/// Get all of the GroupId values from the TestSetupGroups table with this TestSetupId
/// </summary>
/// <param name="testSetupId">The value that corresponds to the column in the TestSetups table</param>
/// <returns></returns>
private List<int> GetGroupIds(int testSetupId)
{
var groupIds = new List<int>();
var hresult = DbOperations.TestSetupGroupsGet(null, Id, null, out var records);
if (0 == hresult && null != records && records.Any())
{
foreach (var record in records)
{
groupIds.Add(record.GroupId);
}
}
return groupIds;
}
/// <summary>
/// Get the id from the Sensors table with this serial number
/// </summary>
/// <param name="channelName">The serial number of the sensor on this channel</param>
/// <returns></returns>
private Dictionary<int, int> GetSensorId(string channelName)
{
var IdAndType = new Dictionary<int, int>();
var hresult = DbOperations.SensorsGet(channelName, out var records);
if (0 == hresult && null != records && records.Any())
{
foreach (var record in records)
{
IdAndType[record.id] = record.SensorType;
}
}
return IdAndType;
}
/// <summary>
/// Get the DASId and DASChannelIndex values from the Channels table with this GroupId and SensorId
/// </summary>
/// <param name="groupId">The value that matches the column in the Groups table</param>
/// <param name="sensorId">The value that matches the column in the Sensors table</param>
/// <returns>A list of DASId/DASChannelIndex tuples (hopefully a list of length 1)</returns>
private List<Tuple<int, int>> GetDASIdAndDASChannelIndex(int groupId, int sensorId)
{
var dasIdAndChannelIndexList = new List<Tuple<int, int>>();
var hresult = DbOperations.ChannelsGet(null, groupId, null, null, null, null, out var records);
if (0 == hresult && null != records && records.Any())
{
foreach (var record in records)
{
if (record.SensorId == sensorId)
{
var dasAndChannelIndex = new Tuple<int, int>(record.DASId, record.DASChannelIndex);
dasIdAndChannelIndexList.Add(dasAndChannelIndex);
}
}
}
return dasIdAndChannelIndexList;
}
/// <summary>
/// Get the SerialNumber and ParentDAS from the DAS table and combine with DASChannelIndex from Channels table
/// and the channelName before storing ([SPE00596:SPS01235] CH-04\\an1)
/// </summary>
/// <param name="dasId">The value that matches the column in the DAS table</param>
/// <returns></returns>
private string GetDASSerialNumber(int dasId)
{
var hresult = DbOperations.DASGet(null, null, out var records);
if (0 == hresult && null != records && records.Any())
{
foreach (var record in records)
{
var foundDASId = record.DASId;
if (foundDASId == dasId)
{
var dasString = "";
var parentDAS = record.ParentDAS;
if (parentDAS != "")
{
dasString = $"{parentDAS}:";
}
dasString = $"{dasString}{record.SerialNumber}";
return dasString;
}
}
}
return "";
}
private IReadOnlyDictionary<long, IGroupChannel> GetChannelIdToChannelLookup()
{
var lookup = new Dictionary<long, IGroupChannel>();
foreach (var group in Groups)
{
var channels = ChannelsForGroup[group];
foreach (var ch in channels)
{
if (ch.IsBlank())
{
continue;
}
if (ch.IsDisabled)
{
continue;
}
if (!ch.SensorValid)
{
continue;
}
lookup[ch.Id] = ch;
}
}
return lookup;
}
private void LoadGraphsFromDb()
{
var lookup = GetChannelIdToChannelLookup();
var graphs = new List<TestGraph>();
using (var sql = DbOperations.GetSQLCommand(true))
{
var hresult = DbOperations.TestGraphsGet(null, Id, out var records);
if (0 == hresult && null != records && records.Any())
{
foreach (var record in records)
{
graphs.Add(new TestGraph(record, lookup));
}
}
}
TestGraphs = graphs.ToArray();
}
/// <summary>
/// replaces one das in the test setup with a different one
/// </summary>
public void ReplaceDAS(DASHardware source, DASHardware dest)
{
var allHardware = DASHardwareList.GetAllHardware();
var lookup = new Dictionary<int, IDASHardware>();
foreach (var h in allHardware) { lookup[h.DASId] = h; }
dest.ReconfigureAsNeeded(source);
DASHardwareList.GetList().Commit(dest);
AddHardware(dest.DASId, dest.SerialNumber, allHardware, lookup);
//the sample rate of the test is default, but if the old hardware had a specific rate set,
//we'd like to use that
var rate = SamplesPerSecondAggregate;
if (DASSampleRateList.ContainsKey(source.SerialNumber))
{
rate = DASSampleRateList[source.SerialNumber];
}
DASSampleRateList[dest.SerialNumber] = rate;
var channels = GetChannels();
foreach (var ch in channels)
{
if (ch.DASId != source.DASId) { continue; }
if (ch.DASChannelIndex >= 0)
{
var replacementChannel = dest.Channels[ch.DASChannelIndex];
ch.SetHardwareChannel(replacementChannel);
}
}
RemoveHardware(source.DASId, allHardware, lookup);
ClearHardware();
}
#region Validate
public static bool ValidateTestSetupName(ref List<string> errors, TestTemplate CurrentTestSetup)
{
if (string.IsNullOrWhiteSpace(CurrentTestSetup.Name))
{
errors.Add(StringResources.EditTestSetup_NameRequired);
return false;
}
if (CurrentTestSetup.Name == StringResources.QuickSensorCheck_DefaultTestName &&
!CurrentTestSetup.QuickSensorCheck)
{
errors.Add(StringResources.QuickSensorCheck_DefaultTestNameInvalid);
return false;
}
if (DiskUtility.ValidateFileAndPathNameChars(CurrentTestSetup.Name))
{
var nameToCheck = CurrentTestSetup.Name.ToLower();
if (nameToCheck.Equals("iso") || nameToCheck.Equals("csv") || nameToCheck.Equals("realtime"))
{
errors.Add(StringResources.EditTestSetup_NameCannotBeISOCSVOrRealtime);
return false;
}
var encoding = Encoding.GetEncoding("UTF-8");
var nameInBytes = encoding.GetBytes(nameToCheck);
if (nameInBytes.Length == nameToCheck.Length) return true;
errors.Add(StringResources.EditTestSetup_NameCannotContainDoubleByteCharacters);
return false;
}
errors.Add(StringResources.EditTestSetup_NameContainsInvalidCharacters);
//fatal
return false;
}
public static bool Validate(ref List<string> errors, ref List<string> warnings, bool displayWindow, TestTemplate CurrentTestSetup, bool bValid,
StrictLevel strictness, bool bWarnOnNotFullyAssigned, bool bRefreshHardware, bool warnWhenRun)
{
if (!Validate(ref errors, ref warnings, displayWindow, CurrentTestSetup, bValid, strictness, true,
bWarnOnNotFullyAssigned, bRefreshHardware, warnWhenRun))
{
CurrentTestSetup.SetIsComplete(false);
return false;
}
if (errors.Any())
{
CurrentTestSetup.SetIsComplete(false);
return true; //Save it incomplete
}
CurrentTestSetup.SetIsComplete(true);
return true;
}
private SensorCalibration GetSensorCalibration(SensorData sd, ExcitationVoltageOptions.ExcitationVoltageOption preferredExcitation)
{
return SensorCalibration.GetLatestCalibrationBySerialNumberAndExcitation(sd, preferredExcitation);
}
/// <summary>
/// validates that the sensor is ok to use
/// [only handles analog sensors and calibration currently]
/// </summary>
/// <param name="setup"></param>
/// <param name="sd"></param>
/// <param name="warnings"></param>
/// <param name="errors"></param>
/// <returns></returns>
public static bool ValidateSensor(SensorData sd, ref List<string> warnings, ref List<string> errors, IGroupChannel channel, StrictLevel strictness)
{
if (null == sd)
{
var error = string.Format(StringResources.EditTestSetupPageError_MissingSensor,
channel.GetChannelName(SerializedSettings.ISOViewMode));
warnings.Add(error);
return false;
}
//we only care about analog sensors currently
if (sd.IsSquib()) { return true; }
if (sd.IsDigitalInput()) { return true; }
if (sd.IsDigitalOutput()) { return true; }
if (sd.IsUart()) { return true; }
if (sd.IsStreamOutput()) { return true; }
if (sd.IsStreamInput()) { return true; }
if (sd.IsThermocoupler()) { return true; }
if (sd.IsCan()) { return true; }
//For embedded sensors, calibration is done on a DAS basis.
if (sd.IsTestSpecificEmbedded || sd.IsTestSpecificEmbeddedClock || sd.IsTestSpecificThermo) { return true; }
var bValid = true;
if (SerializedSettings.DontAllowDataCollectionIfOverused)
{
//Validate sensor based on usage
if (sd.UsageCount >= sd.MaximumUsage)
{
var error = string.Format(StringResources.EditObjectPageError_UsageExceeded,
channel.GetChannelName(SerializedSettings.ISOViewMode), sd.SerialNumber, sd.MaximumUsage);
if (!errors.Contains(error))
{
errors.Add(error);
}
bValid = false;
}
else if (sd.UsageCount >= (sd.MaximumUsage - SerializedSettings.UsageRemainingForWarning))
{
//just warn
var warning = string.Format(StringResources.EditObjectPageWarning_UsageAlmostExceeded,
channel.GetChannelName(SerializedSettings.ISOViewMode), sd.SerialNumber, sd.MaximumUsage - sd.UsageCount);
if (!warnings.Contains(warning))
{
warnings.Add(warning);
}
}
}
var sc = SensorCalibrationList.GetLatestCalibrationBySerialNumber(sd);
if (null == sc)
{
var error = string.Format(StringResources.EditTestSetupPage_MissingCalibration,
channel.GetChannelName(SerializedSettings.ISOViewMode), sd.SerialNumber);
warnings.Add(error);
return false;
}
else
{
if (Array.Exists(sc.ZeroMethods.Methods, method => method.Method == ZeroMethodType.AverageOverTime && method.Start >= method.End))
{
errors.Add($"{StringResources.TestSetupError_InvalidZeroStartTime} {sd.ToDisplayString()}");
bValid = false;
}
if ((sc.LinearAdded && 0 == sc.LinearAddedSensitivity) || Array.Exists(sc.Records.Records, r => 0 == r.Sensitivity))
{
var error = string.Format(StringResources.TestTemplate_InvalidSensitivity,
channel.GetChannelName(SerializedSettings.ISOViewMode), sd.SerialNumber);
errors.Add(error);
}
}
// 13065 Sensor "First Use" Date
var dueDate = sd.GetDueDate(sc);
var warningDate = dueDate.AddDays(-1D * SerializedSettings.SensorCalWarningPeriodDays);
if (StrictLevel.CheckoutOnly != strictness
&& dueDate.Date < DateTime.Now.Date)
{
if (SerializedSettings.CalSensorPolicy == SensorConstants.SensorCalPolicy.AllowAlways || strictness == StrictLevel.QuickCheckout)
{
//just warn
var warning = string.Format(StringResources.EditObjectPageWarning_CalibrationOverdue,
channel.GetChannelName(SerializedSettings.ISOViewMode), sd.SerialNumber);
if (!warnings.Contains(warning))
{
warnings.Add(warning);
}
}
else
{
var error = string.Format(StringResources.EditObjectPageError_CalibrationOverdue,
channel.GetChannelName(SerializedSettings.ISOViewMode), sd.SerialNumber);
if (!errors.Contains(error))
{
errors.Add(error);
}
bValid = false;
}
}
else if (StrictLevel.CheckoutOnly != strictness
&& warningDate.Date <= DateTime.Now.Date)
{
var warning = string.Format(StringResources.EditObjectPageWarning_CalibrationDueSoon,
channel.GetChannelName(SerializedSettings.ISOViewMode), sd.SerialNumber,
dueDate.ToLongDateString());
if (!warnings.Contains(warning))
{
warnings.Add(warning);
}
}
return bValid;
}
private static void ValidateTestObjectAndPositionFields(ref List<string> errors, ref List<string> warnings,
TestTemplate testSetup)
{
var channels = testSetup.GetChannels();
var validTestObjects = SerializedSettings.GetValidISOTestObjects();
var validPositions = SerializedSettings.GetValidISOPositions().ToList();
var viewMode = SerializedSettings.ISOViewMode;
foreach (var channel in channels)
{
if (channel.IsDisabled || channel.IsBlank()) { continue; }
var code = new DTS.Common.ISO.IsoCode(channel.IsoCode);
if (!validTestObjects.Contains(code.TestObject))
{
var msg = string.Format(StringResources.InvalidTestObject, code.TestObject,
channel.GetChannelName(viewMode));
if (!errors.Contains(msg))
{
errors.Add(msg);
}
}
if (!validPositions.Contains(code.Position))
{
var msg = string.Format(StringResources.InvalidPosition, code.Position,
channel.GetChannelName(viewMode));
if (!errors.Contains(msg))
{
errors.Add(msg);
}
}
}
}
/// <summary>
/// validates whether the test contains Stand-In DAS or not, a test containing Stand-In DAS is not
/// ready to run
///16340 [old 16330] DataPRO 3.1 - Generic DAS/Replace DAS
/// </summary>
private static void ValidateStandIn(DASHardware h, ref List<string> errors)
{
if (h.IsStandIn() && !errors.Contains(StringResources.EditTestSetupPage_NoPhysicalHardwareInTest))
{
errors.Add(StringResources.EditTestSetupPage_NoPhysicalHardwareInTest);
}
}
/// <summary>
/// validates whether all hardware supports start/trigger completion modes
/// (really only needs to test if either start or trigger is inverted)
/// </summary>
/// <param name="errors">any errors discovered during validation</param>
/// <param name="warnings">any warnings discovered during validation</param>
/// <param name="test">the test to validate</param>
private static void ValidateEventLineCompletionModes(ref List<string> errors, ref List<string> warnings, TestTemplate test)
{
//if test doesn't have invert set, there's nothing to test, we only need to test if we are inverting a signal
if (!test.InvertStartRecordCompletion && !test.InvertTriggerCompletion) { return; }
var hardware = test.GetHardware();
//this will hold das serials for any das not supporting a completion mode
var list = new List<string>();
foreach (var h in hardware)
{
if (test.InvertStartRecordCompletion)
{
if (!HardwareConstants.SupportsStartInversion(h.DASTypeEnum, h.ProtocolVersion))
{
if (!list.Contains(h.ToString())) { list.Add(h.ToString()); }
}
}
if (test.InvertTriggerCompletion)
{
if (!HardwareConstants.SupportsTriggerInversion(h.DASTypeEnum, h.ProtocolVersion))
{
if (!list.Contains(h.ToString())) { list.Add(h.ToString()); }
}
}
}
if (list.Any())
{
var msg = $"{StringResources.Warning_UnsupportedEventLineCompletion}\r\n{string.Join("\r\n", list.ToArray())}";
if (!warnings.Contains(msg)) { warnings.Add(msg); }
}
}
private static void ValidateTOMInIgnoreTrigger(ref List<string> errors, ref List<string> warnings, TestTemplate test)
{
if (null == test) { return; }
//only need to warn when ignore shorted trigger is true ...
if (!test.IgnoreShortedTriggerCompletion) { return; }
if (test.CheckForTOM())
{
if (!warnings.Contains(StringResources.Warning_EditTestIgnoreTriggerTOM))
{
warnings.Add(StringResources.Warning_EditTestIgnoreTriggerTOM);
}
}
}
/// <summary>
/// validates whether the test SetDASToAutoArm setting works with the test's recording mode
/// </summary>
/// <param name="errors">any errors found during validation</param>
/// <param name="warnings">any warnings found during validation</param>
/// <param name="test">test to validate</param>
private static void ValidateAutoArmRecordingMode(ref List<string> errors, ref List<string> warnings, TestTemplate test)
{
//30164 If there is TSR AIR in the test, don't worry about validating for Auto-Arm
//because the checkbox is hidden, and we don't Auto-arm TSR AIRs.
if (!test.DoAutoArm || Array.Exists(test.GetHardware(), hw => hw.IsTSRAIR())) { return; }
if (!RecordingModeExtensions.DoesModeSupportAutoArm(test.RecordingMode))
{
var msg = string.Format(StringResources.Error_RecordingModeDoesntSupportAutoArm, EnumDescriptionTypeConverter.GetEnumDescription(test.RecordingMode));
if (!errors.Contains(msg)) { errors.Add(msg); }
}
}
//FB 28186 Check for license and limit the hardware access,
public static bool ValidateTsrAirLicense(ref List<string> errors, TestTemplate test, DASHardware[] hardware)
{
if (test != null)
{
List<DASHardware> selectedHardware = hardware.ToList();
var licenseValidationResult = ApplicationProperties.LicenseValidationResult;
if (selectedHardware.Exists(p => !p.IsTSRAIR()) && licenseValidationResult.LicenseType == DataProLicensingEnums.LicenseType.TSRAir)
{
var nonTsrDas = selectedHardware.Where(p => !p.IsTSRAIR()).Select(p => p.DASSerialNumber);
var nonTsrDasStr = string.Join(",", nonTsrDas);
errors.Add(string.Format(StringResources.EditTestSetup_TSRAIRLicenseLimitationError, nonTsrDasStr));
//mark the test as incomplete in DB if the license is not valid for hardware
_ = DbOperations.TestSetupsMarkIsCompleteIsDirty(test.Name, false, false, nonTsrDasStr);
return false;
}
}
return true;
}
/// <summary>
/// returns the max streaming rate that digital filter rates are supported at
/// http://manuscript.dts.local/f/cases/30273/Implement-Warning-Validation-for-Streaming-sample-rate-greater-than-10k-when-Digital-Filtering-is-configured
/// http://manuscript.dts.local/f/cases/39106/Datapro-shouldnt-be-warning-about-digital-filter-availability-until-20k-sps
/// this is just a warning and it's only done for S6A (not S6A-BR by LP's suggestion)
/// </summary>
/// <param name="test"></param>
/// <returns></returns>
private static double GetMaxDigitalFilterStreamRate(TestTemplate test)
{
if (null == test)
{
return Constants.SLICE6AIR_STREAMING_DIGITAL_FILTERING_MAX_SAMPLERATE;
}
try
{
var allHardware = test.GetHardware();
foreach (var h in allHardware)
{
if (h.GetHardwareTypeEnum() == HardwareTypes.SLICE6_AIR &&
h.ProtocolVersion < Constants.SLICE6AIR_20K_DIGITAL_FILTER_MIN_PROTOCOL)
{
return Constants.SLICE6AIR_STREAMING_DIGITAL_FILTERING_MAX_SAMPLERATE;
}
}
return Constants.SLICE6AIR_STREAMING_DIGITAL_FILTERING_MAX_SAMPLERATE_20k;
}
catch (Exception ex)
{
APILogger.Log(ex);
return Constants.SLICE6AIR_STREAMING_DIGITAL_FILTERING_MAX_SAMPLERATE;
}
}
/// <summary>
/// checks if isocode on channel already appears in list of isocodes in test setup
/// </summary>
/// <param name="errors"></param>
/// <param name="ch"></param>
/// <param name="usedISOCodesLookup"></param>
private static void DoDuplicateIsoCodeCheck(ref List<string> errors,
IGroupChannel ch, ref Dictionary<string, bool> usedISOCodesLookup)
{
//these type of channels don't have isocodes that we care about
//however until a sensor is assigned we can't tell the bridge type, so only bypass if a sensor is assigned
if (null != ch.SensorData && (ch.IsDigitalOut || ch.IsStreamOut || ch.IsUart || ch.IsStreamIn)) { return; }
if (usedISOCodesLookup.ContainsKey(ch.IsoCode))
{
var channelName = ChannelHelper.GetWarningChannelName(ch);
var err = string.Format(StringResources.EditObjectPageError_DuplicateIsoCode, channelName);
//we put this into errors because it's fatal for running the test, but we
//don't return false because we CAN save the test ...
//13902 Cannot save test setup when leaving out one or more characters for a channels' ISO code
if (!errors.Contains(err))
{
errors.Add(err);
}
}
else
{
usedISOCodesLookup[ch.IsoCode] = true;
}
}
private static void ValidateTSRAIRRanges(ref List<string> _, ref List<string>warnings, TestTemplate test)
{
if (null == test) { return; }
var channels = test.GetChannels();
var invalidLowG = channels.Exists(x => null != x.HardwareChannel && x.RangeModifiableSensorLowG && x.Range < SensorConstants.LowG64);
var invalidARS = channels.Exists(x => null != x.HardwareChannel && x.RangeModifiableSensorARS && x.Range < SensorConstants.ARS2000);
if (invalidLowG)
{
var msg = StringResources.TSRAIR_InvalidLowG;
if (!warnings.Contains(msg)) { warnings.Add(msg); }
}
if (invalidARS)
{
var msg = StringResources.TSRAIR_InvalidARS;
if (!warnings.Contains(msg)) { warnings.Add(msg); }
}
}
private static void ValidateEuAtMv(ref List<string> warnings, TestTemplate test)
{
if ( null == test) { return; }
var channels = test.GetChannels();
foreach( var channel in channels)
{
ValidateEuAtMvChannel(channel, warnings);
}
}
private static void ValidateEuAtMvChannel(IGroupChannel channel, List<string> warnings)
{
if (null == channel) { return; }
if (!channel.IsAnalog) { return; }
if (null == channel.InitialOffset) { return; }
if (channel.InitialOffset.Form != InitialOffsetTypes.EUAtMV) { return; }
if (channel.ZeroMethod == ZeroMethodType.None) { return; }
warnings.Add(string.Format(StringResources.Warning_EuAtMvUseNone, channel.GetChannelName(RunTestVariables.ISOViewMode)));
}
/// <summary>
/// returns true if digital filter is being used
/// </summary>
/// <param name="dspFilter"></param>
/// <returns></returns>
private static bool IsDSPFiltered(IStreamingFilterProfile dspFilter)
{
return dspFilter == null || DSPFilterCollection.NONE != dspFilter.EnumValue;
}
public static bool Validate(ref List<string> errors, ref List<string> warnings, bool displayWindow, TestTemplate CurrentTestSetup,
bool bValid, StrictLevel strictness, bool markIsCompleteUnchecked, bool bWarnOnNotFullyAssigned, bool bRefreshHardware, bool warnWhenRun)
{
try
{
ValidateEuAtMv(ref warnings, CurrentTestSetup);
ValidateTSRAIRRanges(ref errors, ref warnings, CurrentTestSetup);
ValidateAutoArmRecordingMode(ref errors, ref warnings, CurrentTestSetup);
ValidateEventLineCompletionModes(ref errors, ref warnings, CurrentTestSetup);
ValidateTOMInIgnoreTrigger(ref errors, ref warnings, CurrentTestSetup);
var viewMode = SerializedSettings.ISOViewMode;
if (SerializedSettings.ValidateTestPositionAndTestObject && SerializedSettings.ShowISOCodes
&& StrictLevel.CheckoutOnly != strictness && StrictLevel.QuickCheckout != strictness) //15139, ignore ISO warnings in quick checkout
{
if (viewMode == IsoViewMode.ISOAndUserCode || viewMode == IsoViewMode.ISOOnly)
{
ValidateTestObjectAndPositionFields(ref errors, ref warnings, CurrentTestSetup);
}
}
var serialNumbersProcessed = new Dictionary<string, bool>();
var eidsProcessed = new Dictionary<string, bool>();
var hardwareChannelIdsProcessed = new Dictionary<string, bool>();
var channelLookup = new Dictionary<string, HardwareChannel>();
var usedISOCodesLookup = new Dictionary<string, bool>();
var availableAnalogChannels = 0;
var availableDigitalInputChannels = 0;
var availableDigitalOutputChannels = 0;
var availableSquibChannels = 0;
var hardware = CurrentTestSetup.GetHardware();
if (!ValidateTsrAirLicense(ref errors, CurrentTestSetup, hardware))
{
//Test is not valid if the license is not valid
bValid = false;
}
bool bHasHardware = false;
bool bHasChannels = false;
foreach (var h in hardware)
{
var hType = h.GetHardwareTypeEnum();
//We want to check the calibration dates on some hardware where
//IsSLICEEthernetController is True (PowerPRO, for example).
ValidateHardware(h, false, ref warnings, ref errors);
//17744 Is standin check and warning is being skipped for ethernet controllers and powerpro
ValidateStandIn(h, ref errors);
if (h.IsSLICEEthernetController) { continue; }
bHasHardware = true;
if (CurrentTestSetup.DoAutoArm)
{
switch (hType)
{
case HardwareTypes.TDAS_Pro_Rack:
case HardwareTypes.TDAS_LabRack:
case HardwareTypes.G5INDUMMY:
case HardwareTypes.G5VDS:
errors.Add(StringResources.EditTestSetupPage_HardwareDoesNotSupportAutoArm);
break;
}
}
else if (CurrentTestSetup.DoStreaming)
{
if (hType != HardwareTypes.SLICE6_AIR_BR && hType != HardwareTypes.SLICE6_AIR && hType != HardwareTypes.SLICE6_Base &&
hType != HardwareTypes.TSR_AIR && hType != HardwareTypes.TSR_AIR_RevB /* && hType != HardwareTypes.SLICE6DB_AIR*/ &&
hType != HardwareTypes.SLICE6_AIR_TC)
{
errors.Add(StringResources.EditTestSetupPage_HardwareDoesNotSupportStreaming);
}
//30273 Implement 'Warning' Validation for Streaming sample rate greater than 10k when Digital Filtering is configured
//39106 [allow 20k]
if (hType == HardwareTypes.SLICE6_AIR &&
IsDSPFiltered(SerializedSettings.GetDefaultDSP())
&&
CurrentTestSetup.DASSampleRateList.ContainsKey(h.SerialNumber) )
{
var minDigitalFilterStreamRate = GetMaxDigitalFilterStreamRate(CurrentTestSetup);
if (CurrentTestSetup.DASSampleRateList[h.SerialNumber] > minDigitalFilterStreamRate)
{
if (warnWhenRun)
{
errors.Add(string.Format(StringResources.EditTestSetupPage_InvalidDigitalFilteringSampleRate,
minDigitalFilterStreamRate, Environment.NewLine));
}
else
{
warnings.Add(string.Format(StringResources.EditTestSetupPage_InvalidDigitalFilteringSampleRate,
minDigitalFilterStreamRate, Environment.NewLine));
}
}
}
}
var foo = CurrentTestSetup.DASSampleRateList;
if (CurrentTestSetup.UARTRecordingMode && CurrentTestSetup.DASSampleRateList[h.SerialNumber] > Constants.UART_MODE_MAX_SAMPLERATE)
{
errors.Add(StringResources.EditTestSEtupInfo_InvalidSampleRate);
}
for (var i = 0; i < h.Channels.Length; i++)
{
var ch = h.Channels[i];
var key = $"{ch.Hardware.DASId}_{ch.ChannelNumber}";
if (channelLookup.ContainsKey(key)) continue;
channelLookup.Add(key, ch);
if (ch.IsSupportedBridgeType(SensorConstants.BridgeType.SQUIB))
{
availableSquibChannels++; i++; /*bypass next channel as it's also a squib*/
}
else if (ch.IsSupportedBridgeType(SensorConstants.BridgeType.DigitalInput))
{ availableDigitalInputChannels++; }
else if (ch.IsSupportedBridgeType(SensorConstants.BridgeType.TOMDigital))
{ availableDigitalOutputChannels++; }
else { availableAnalogChannels++; }
}
}
if (!bHasHardware && bWarnOnNotFullyAssigned)
{
errors.Add(StringResources.EditTestSetupPage_NoHardwareInTest);
}
ValidateSquibSettings(CurrentTestSetup, ref errors, ref warnings);
ValidateStreamUDPSettings(CurrentTestSetup, ref errors);
//13914 Cannot save test setup as incomplete if a channel is not included in any of the multiple ROI periods.
if (CurrentTestSetup.RegionsOfInterest.Count > 1 && CurrentTestSetup.DoROIDownload)
{
foreach (var region in CurrentTestSetup.RegionsOfInterest)
{
if (null == region.ChannelIds || !region.ChannelIds.Any())
{
//No channel ids, but we might have called into an old database, so check for channel names too
if (null == region.ChannelNames || !region.ChannelNames.Any())
{
errors.Add(string.Format(StringResources.TestTemplate_ROIHasNoChannels, region.Suffix));
}
}
}
}
var uniqueISOCodesRequired = SerializedSettings.UniqueISOCodesRequired && strictness != StrictLevel.QuickCheckout;
//FB 18875 use for chache
var cals = SensorsCollection.GetLatestCalibrations();
var sensorCalPolicy = CalibrationPolicy.GetCalibrationPolicy();
foreach (var group in CurrentTestSetup.Groups)
{
var channels = CurrentTestSetup.ChannelsForGroup[group];
foreach (var ch in channels)
{
if (ch.IsBlank() || ch.IsDisabled)
{
continue;
}
if (StrictLevel.CheckoutOnly != strictness
&& uniqueISOCodesRequired
&& (viewMode == IsoViewMode.ISOAndUserCode || viewMode == IsoViewMode.ISOOnly)
&& !ch.IsUart && !ch.IsStreamOut && !ch.IsStreamIn)
{
if (ch.IsoCode.Length < 16)
{
var msg = string.Format(StringResources.EditTestSetup_WarningISOCodeInvalid, ch.IsoCode);
if (!warnings.Contains(msg))
{
warnings.Add(msg);
}
}
}
if ((CurrentTestSetup.ExportFormats & SupportedExportFormatBitFlags.toyotaunfiltered) == SupportedExportFormatBitFlags.toyotaunfiltered)
{
foreach (var setting in ch.ChannelSettings)
{
if (setting.SettingName != DbOperations.TestSetups.SettingsFields.UserValue2.ToString()) continue;
if (!string.IsNullOrWhiteSpace(setting.Value) && !double.TryParse(setting.Value, out double cableMultiplier))
{
warnings.Add(StringResources.EditTestSetup_TTSUserValue2);
if (!SerializedSettings.ShowSensorChannelUserValues)
{
warnings.Add(StringResources.EditTestSetup_ShowSensorChannelUnchecked);
}
break;
}
}
}
if (uniqueISOCodesRequired && (viewMode == IsoViewMode.ISOAndUserCode || viewMode == IsoViewMode.ISOOnly))
{
DoDuplicateIsoCodeCheck(ref errors, ch, ref usedISOCodesLookup);
}
if (!ch.SensorValid)
{
if (!errors.Contains(StringResources.EditTestSetupPage_NoSensorOnChannel) &&
bWarnOnNotFullyAssigned)
{
errors.Add(StringResources.EditTestSetupPage_NoSensorOnChannel);
}
}
else
{
bHasChannels = true;
//FB 18875 use for chache
var sensor = CurrentTestSetup.GetSensor(ch, cals);
if (null == sensor)
{
var err = string.Format(StringResources.EditTestSetupPage_CouldNotFindSensor,
ch.SensorId, ch.GetChannelName(SerializedSettings.ISOViewMode), ch.GroupName);
if (!errors.Contains(err))
{
errors.Add(err);
}
return false;
}
//Set the sensor's Usage Count before validation
sensor.UsageCount = sensor.GetLatestCalibration()?.UsageCount ?? 0;
ValidateSensor(sensor, ref warnings, ref errors, ch, strictness);
if (sensor.Broken || sensor.DoNotUse)
{
var error = string.Format(StringResources.EditTestSetupPageError_MissingSensor,
ChannelHelper.GetWarningChannelName(ch));
if (!warnings.Contains(error) && !errors.Contains(error)) { errors.Add(error); }
continue;
}
//33237 Don't unassign multiple ROI channels if Compact is selected in Hardware step
//36746 Don't throw exception during TTS import due to null SensorData
if (CurrentTestSetup.RegionsOfInterest.Count > 1 && !CurrentTestSetup.RegionsOfInterest.Any(roi => roi.ChannelIds.Contains(ch.Id))
&& !sensor.IsDigitalOutput() && !sensor.IsTestSpecificDigitalOutput)//FB14896: scrub digital outs from ROI
{
var msg = string.Format(StringResources.TestTemplate_ChannelNoROIs, ch.GetChannelName(SerializedSettings.ISOViewMode), ch.Hardware);
if (!errors.Contains(msg)) errors.Add(msg);
//13914 Cannot save test setup as incomplete if a channel is not included in any of the multiple ROI periods.
}
if (eidsProcessed.ContainsKey(sensor.EID))
{
//FB15726: make sure EID and serials are validated in TestTemplate and UI
var msg = string.Format(
StringResources.EditTestSetupPage_DuplicateSensorId,
sensor.EID, sensor.SerialNumber);
if (!errors.Contains(msg)) errors.Add(msg);
return false;
}
if (!string.IsNullOrWhiteSpace(sensor.EID)) eidsProcessed.Add(sensor.EID, true);
if (serialNumbersProcessed.ContainsKey(sensor.SerialNumber))
{
//FB15726: Allow "reusable sensors", or sensors without EID to appear more than once in a test
if (sensor.IsTestSpecificDigitalOutput || sensor.IsTestSpecificSquib || sensor.IsTestSpecificDigitalIn || sensor.IsTestSpecificEmbedded || sensor.IsTestSpecificEmbeddedClock ||
string.IsNullOrWhiteSpace(sensor.EID) || sensor.IsTestSpecificThermo)
{
continue;
}
}
serialNumbersProcessed.Add(sensor.SerialNumber, true);
if (sensor.IsSquib())
{
availableSquibChannels--;
if (sensor.SquibFireDelayMS + sensor.SquibFireDurationMS >
CurrentTestSetup.PostTriggerSeconds * 1000)
{
errors.Add(string.Format(
StringResources.TestTemplate_InsufficientPostTriggerLength,
sensor.SerialNumber, ch.GetChannelName(SerializedSettings.ISOViewMode)));
}
}
else if (sensor.IsDigitalInput())
{
availableDigitalInputChannels--;
}
else if (sensor.IsDigitalOutput())
{
availableDigitalOutputChannels--;
if (sensor.DigitalOutputDelayMS + sensor.DigitalOutputDurationMS >
CurrentTestSetup.PostTriggerSeconds * 1000)
{
errors.Add(string.Format(
StringResources.TestTemplate_InsufficientPostTriggerLength,
sensor.SerialNumber, ch.GetChannelName(SerializedSettings.ISOViewMode)));
}
}
else
{
availableAnalogChannels--;
}
if (sensor != null)
{
if (StrictLevel.CheckoutOnly != strictness
&& (viewMode == IsoViewMode.ISOAndUserCode || viewMode == IsoViewMode.ISOOnly)
&& !sensor.IsUart()
&& !sensor.IsTestSpecificUart
&& !sensor.IsStreamOutput()
&& !sensor.IsTestSpecificStreamOutput
&& !sensor.IsStreamInput()
&& !sensor.IsCan()
&& !sensor.IsTestSpecificStreamInput
&& !sensor.IsTestSpecificEmbeddedClock) //Embedded clocks & settings sensors aren't coded sensors
{
var sensorDimension = (new DTS.Common.ISO.IsoCode(sensor.ISOCode)).PhysicalDimension;
var channelDimension = (new DTS.Common.ISO.IsoCode(ch.IsoCode)).PhysicalDimension;
if (sensor.IncompatibleSensorAssignment(sensorDimension, channelDimension))
{
var err = string.Format(
StringResources.EditTestSetupPage_IncompatibleSensorNotSupported,
sensorDimension,
sensor.SerialNumber,
channelDimension,
ch.GetChannelName(SerializedSettings.ISOViewMode), ch.GroupName);
switch (SerializedSettings.IsoChannelSensorCompatibilityLevel)
{
case IsoChannelSensorCompatibilityLevels.DontAllow:
if (!errors.Contains(err))
{
errors.Add(err);
}
bValid = false;
break;
case IsoChannelSensorCompatibilityLevels.Warn:
if (!warnings.Contains(
StringResources.EditObjectSensorsControl_Warning + ": " + err))
{
warnings.Add(StringResources.EditObjectSensorsControl_Warning +
": " + err);
}
break;
}
}
//13312 Cannot run my test that was migrated from 1.4 because my digital output channel doesn't contain 16 characters.
//warn if we have incomplete iso except for digital outputs
if (SerializedSettings.UniqueISOCodesRequired && ch.IsoCode.Length != 16
&& !sensor.IsDigitalOutput() && !sensor.IsUart() && !sensor.IsStreamInput() && !sensor.IsStreamOutput() && !sensor.IsCan()
&& strictness != StrictLevel.QuickCheckout)
{
var channelName = ChannelHelper.GetWarningChannelName(ch);
var err = string.Format(StringResources.EditObjectPageError_IncompleteIsoCode, channelName);
if (!errors.Contains(err))
{
errors.Add(err);
}
bValid = false;
}
}
if (!sensor.IsTestSpecificEmbedded && !sensor.IsTestSpecificEmbeddedClock && !sensor.IsTestSpecificThermo) //Validation of calibration for embedded sensors is done at the DAS-level
{
SensorCalibration sc = null;
var preferredExcitation = ExcitationVoltageOptions.ExcitationVoltageOption.Undefined;
if (sensor.SupportedExcitation.Any())
{
preferredExcitation = sensor.SupportedExcitation[0];
}
else
{
bValid = false;
var err = string.Format(StringResources.EditTestSetupPage_MissingExcitation,
ch.GetChannelName(SerializedSettings.ISOViewMode), sensor.SerialNumber);
if (!errors.Contains(err))
{
errors.Add(err);
}
}
if (preferredExcitation != ExcitationVoltageOptions.ExcitationVoltageOption.Undefined)
{
sc = CurrentTestSetup.GetSensorCalibration(sensor, preferredExcitation);
if (null == sc)
{
bValid = false;
var err = string.Format(StringResources.EditTestSetupPage_MissingCalibration,
ch.GetChannelName(SerializedSettings.ISOViewMode), sensor.SerialNumber);
if (!errors.Contains(err))
{
errors.Add(err);
}
}
else
{
var now = DateTime.Now;
var days = sensor.GetDueDate(sc).Subtract(now).TotalDays;
if (StrictLevel.CheckoutOnly != strictness
&& sensorCalPolicy.SelectedCalPolicy == SensorConstants.SensorCalPolicy.DONT_ALLOW
&& (days <= 0 || days < sensorCalPolicy.WarningPeriod))
{
var err = string.Format(StringResources.OverdueSensors_CalibrationDateOverdueOrNear,
ch.GetChannelName(SerializedSettings.ISOViewMode), sensor.SerialNumber);
if (days <= 0)
{
if (!errors.Contains(err)) { errors.Add(err); }
}
else if (!warnings.Contains(err)) { warnings.Add(err); }
}
}
}
}
}
if (!ch.HardwareValid) continue;
var key = $"{ch.DASId}_{ch.DASChannelIndex}";
if (!channelLookup.ContainsKey(key))
{
var err = string.Format(StringResources.EditTestSetupPage_InvalidHardware,
ch.GetChannelName(SerializedSettings.ISOViewMode), ch.GroupName);
ch.SetHardwareChannel(null);
if (!errors.Contains(err))
{
errors.Add(err);
var eventAggregator = ContainerLocator.Container.Resolve<IEventAggregator>();
eventAggregator.GetEvent<PageModifiedEvent>().Publish(new PageModifiedArg(PageModifiedArg.Status.Modified, null));
}
}
else
{
if (hardwareChannelIdsProcessed.ContainsKey(key))
{
bValid = false;
var err = string.Format(
StringResources.EditTestSetupPage_HardwareAlreadyInUse, ch.GetChannelName(SerializedSettings.ISOViewMode),
ch.GroupName);
if (!errors.Contains(err))
{
errors.Add(err);
}
}
else
{
hardwareChannelIdsProcessed.Add(key, true);
var hch = channelLookup[key];
if (sensor.ByPassFilter &&
((hch.Hardware.GetHardwareTypeEnum() != HardwareTypes.TDAS_Pro_Rack) &&
(hch.Hardware.GetHardwareTypeEnum() != HardwareTypes.TDAS_LabRack)))
{
var err = string.Format(
StringResources.EditTestSetupPage_BypassAAFilterNotSupported,
ch.GetChannelName(SerializedSettings.ISOViewMode), ch.GroupName);
if (!errors.Contains(err))
{
errors.Add(err);
}
}
else
{
if (hch.IsSupportedBridgeType(sensor.Bridge)) continue;
var err = string.Format(
StringResources.EditTestSetupPage_BridgeNotSupported,
sensor.Bridge.ToString(), ch.GetChannelName(SerializedSettings.ISOViewMode), ch.GroupName);
if (!errors.Contains(err))
{
errors.Add(err);
}
}
}
}
}
}
}
if (!bHasChannels && !CurrentTestSetup.HasOBRDDR()) { errors.Add(StringResources.EditTestSetupPage_NoChannelsInTest); }
if (availableAnalogChannels < 0 && !CurrentTestSetup.AllowMissingSensors && bWarnOnNotFullyAssigned)
{
if (!errors.Contains(StringResources.EditTestSetupPage_NeedMoreAnalogChannels) && !errors.Contains(StringResources.EditTestSetupPage_NoHardwareInTest))
{ errors.Add(StringResources.EditTestSetupPage_NeedMoreAnalogChannels); }
}
if (availableDigitalInputChannels < 0 && !CurrentTestSetup.AllowMissingSensors && bWarnOnNotFullyAssigned)
{
if (!errors.Contains(StringResources.EditTestSetupPage_NeedMoreDigitalInputChannels) && !errors.Contains(StringResources.EditTestSetupPage_NoHardwareInTest))
{ errors.Add(StringResources.EditTestSetupPage_NeedMoreDigitalInputChannels); }
}
if (availableDigitalOutputChannels < 0 && !CurrentTestSetup.AllowMissingSensors && bWarnOnNotFullyAssigned)
{
if (!errors.Contains(StringResources.EditTestSetupPage_NeedMoreDigitalOutputChannels) && !errors.Contains(StringResources.EditTestSetupPage_NoHardwareInTest))
{ errors.Add(StringResources.EditTestSetupPage_NeedMoreDigitalOutputChannels); }
}
if (availableSquibChannels < 0 && !CurrentTestSetup.AllowMissingSensors && bWarnOnNotFullyAssigned)
{
if (!errors.Contains(StringResources.EditTestSetupPage_NeedMoreSquibChannels) && !errors.Contains(StringResources.EditTestSetupPage_NoHardwareInTest))
{ errors.Add(StringResources.EditTestSetupPage_NeedMoreSquibChannels); }
}
if (CurrentTestSetup.RegionsOfInterest.Count > 1 && CurrentTestSetup.RegionsOfInterest.Any(roi => !roi.ChannelNames.Any()))
{
//13391 Too many warnings for the same thing when there are no channels selected for an ROI download
//errors.Add(StringResources.TestTemplate_ROIHasNoChannels);
//bValid = false;
//13914 Cannot save test setup as incomplete if a channel is not included in any of the multiple ROI periods.
}
if (!ValidateTestSetupName(ref errors, CurrentTestSetup)) { bValid = false; }
ValidateCommonStatusLine(ref errors, CurrentTestSetup); //not fatal
ValidateSampleRates(ref errors, CurrentTestSetup); //not fatal
ValidateAAFilterRates(ref errors, ref warnings, CurrentTestSetup, warnWhenRun); //not fatal
ValidateStorageSpace(ref errors, CurrentTestSetup);//not fatal
ValidateRecordingModes(ref errors, ref warnings, CurrentTestSetup); //not fatal
if (StrictLevel.CheckoutOnly != strictness)
{
//15391 Quick-check tile requires level trigger and export settings that can't be configured.
ValidateLevelTriggers(ref errors, CurrentTestSetup); //not fatal
}
ValidateAutoArmAllowability(ref errors, CurrentTestSetup);
ValidateStreamingAllowability(ref errors, CurrentTestSetup);
//30429 Invalidate/fail sooner than Arm step if DAS doesn't have streaming capability/channel (TSR AIR may or may not)
ValidateStreamingSupported(ref errors, CurrentTestSetup);
//30048 Allow multiple udp outs, but display a warning, unless suppressed in the config
if (DataModelSettings.DisplayDuplicateUDPStreamOutWarning)
{
ValidateStreamingOutputAddresses(ref warnings, CurrentTestSetup);
}
if (ValidateStreamingProfiles(ref errors, CurrentTestSetup) && SerializedSettings.EnableStreamingWarnings && DASSamplesPerPacketUpToDate)
{
ValidateSamplesPerPacket(ref warnings, CurrentTestSetup);
}
ValidateClockSyncProfiles(ref errors, CurrentTestSetup);
if (!ValidateCalculatedChannels(ref errors, ref warnings, CurrentTestSetup)) { bValid = false; }
if (!ValidateGraphs(ref errors, ref warnings, CurrentTestSetup)) { bValid = false; }
if (!ValidateTestLength(ref errors, ref warnings, CurrentTestSetup)) { bValid = false; }
if (StrictLevel.CheckoutOnly != strictness)
{
ValidateUploadFolder(ref errors, CurrentTestSetup); //not fatal
}
if (CurrentTestSetup.RecordingMode == RecordingModes.Scheduled ||
CurrentTestSetup.RecordingMode == RecordingModes.Interval)
{
ValidateScheduleStartTime(ref errors, CurrentTestSetup);
if (CurrentTestSetup.RecordingMode == RecordingModes.Interval)
{
ValidateInterval(ref errors, CurrentTestSetup);
}
}
}
catch (Exception ex)
{
bValid = false;
}
return bValid;
}
/// <summary>
/// returns a sensor calibration given a sensor and a hardware channel
/// I couldn't find an abstracted function that already did this although there's similar code repeated in multiple places, like validation
/// in this case it's used when downloaded where the hardware channel should be known, while it might not be known at validation time
/// [you could have a sensor assigned to a channel without hardware assigned to that channel]
/// </summary>
/// <param name="sd"></param>
/// <param name="hc"></param>
/// <returns></returns>
public SensorCalibration GetLatestSensorCalibration(ISensorData sd, IHardwareChannel hc)
{
if (!sd.IsTestSpecificEmbedded && !sd.IsTestSpecificEmbeddedClock && !sd.IsTestSpecificThermo) //Validation of calibration for embedded sensors is done at the DAS-level
{
foreach (var exc in sd.SupportedExcitation)
{
if (exc == ExcitationVoltageOptions.ExcitationVoltageOption.Undefined) { continue; }
if (!hc.IsSupportedExcitation(exc)) { continue; }
var cal = GetSensorCalibration((SensorData)sd, exc);
if (null == cal) { continue; }
return cal;
}
return null;
}
return SensorCalibrationList.GetLatestCalibrationBySerialNumber((SensorData)sd);
}
public static bool ValidateInterval(ref List<string> errors, TestTemplate CurrentTestSetup)
{
//Don't allow an event + the time to re-arm to be longer than the interval between events
if (CurrentTestSetup.PostTriggerSeconds + DFConstantsAndEnums.TIME_TO_REARM_SECONDS >= CurrentTestSetup.IntervalBetweenEventStartsMinutes * 60)
{
errors.Add(Constants.IntervalError);
return false;
}
return true;
}
public static bool ValidateScheduleStartTime(ref List<string> errors, TestTemplate CurrentTestSetup)
{
if (DateTime.Compare(CurrentTestSetup.RTCScheduleStartDateTime, DateTime.UtcNow.AddMinutes(DFConstantsAndEnums.SCHEDULE_AHEAD_IN_MINUTES)) < 0)
{
errors.Add(Constants.ScheduleStartTimeError);
return false;
}
return true;
}
private static void ValidateSquibSettings(TestTemplate CurrentTestSetup, ref List<string> errors, ref List<string> warnings)
{
var channels = CurrentTestSetup.GetChannels();
foreach (var ch in channels)
{
if (ch.IsBlank()) { continue; }
if (!ch.IsSquib) { continue; }
if (!ch.SensorValid) { continue; }
if (ch.SquibFireMode == SquibFireMode.NONE)
{
var msg = string.Format(StringResources.TestTemplate_ChannelNoFireMode,
ch.GetChannelName(SerializedSettings.ISOViewMode));
if (!errors.Contains(msg)) { errors.Add(msg); }
}
//FB 14623 Validation for SquibDelay
if (ch.SquibDelay.HasValue)
{
continue;
}
var channelName = ChannelHelper.GetWarningChannelName(ch);
string warningMessage = string.Format(StringResources.EditTestSetupParameters_EmptySquibDelay, channelName);
if (!warnings.Contains(warningMessage))
{
warnings.Add(warningMessage);
}
}
//FB9812 warn if squib resistance check wanted, but no squibs in test
if (CurrentTestSetup.MeasureSquibResistancesStep && !channels.Exists(ch => ch.IsSquib))
{
if (!warnings.Contains(StringResources.EditTestSetupInfo_NoSquibsToCheck))
{
warnings.Add(StringResources.EditTestSetupInfo_NoSquibsToCheck);
}
}
}
/// <summary>
/// This function will validate the UDP address(es) used by both StreamOut and StreamIn channels.
/// </summary>
/// <param name="CurrentTestSetup"></param>
/// <param name="errors"></param>
/// <param name="warnings"></param>
private static void ValidateStreamUDPSettings(TestTemplate CurrentTestSetup, ref List<string> errors)
{
var channels = CurrentTestSetup.GetChannels();
foreach (var ch in channels)
{
if (ch.IsBlank()) { continue; }
if (!ch.IsStreamIn && !ch.IsStreamOut) { continue; }
if (!ch.SensorValid) { continue; }
foreach (var cs in ch.ChannelSettings)
{
if ((cs.SettingName == ChannelSettingBase.UDP_ADDRESS_IN) ||
(cs.SettingName == ChannelSettingBase.UDP_ADDRESS))
{
Utils.ValidateUDPAddress(cs.Value, ref errors);
}
}
}
}
//http://manuscript.dts.local/f/cases/36728/Restriction-Alert-Test-Execution-for-TSR-AIR-with-Level-Trigger-Below-5g-and-Enabled-Wake-Up-Motion
//per EF, whenever wake up on motion is enabled on a TSR AIR, prevent any level trigger <= 5G
private const double MIN_MOTION_LEVELTRIGGER_TSRAIR = 5;
/// <summary>
/// returns true if there's a level trigger on a TSR AIR channel with 5EU or less
/// </summary>
/// <returns></returns>
public bool HasTSRAIRLevelTriggerLessThan5G()
{
if (null == LevelTriggerChannels || 0 == LevelTriggerChannels.Count) { return false; }
using (var e = LevelTriggerChannels.GetEnumerator())
{
while (e.MoveNext())
{
if (null == e.Current.Value.GroupChannel || null == e.Current.Value.GroupChannel.HardwareChannel
|| !e.Current.Value.GroupChannel.HardwareChannel.IsTSRAIR) { continue; }
if (e.Current.Value.GreaterThanThresholdEU <= MIN_MOTION_LEVELTRIGGER_TSRAIR &&
//we don't really need to check against 0 here, as you can't have a TSR AIR level trigger with a
//value of 0EU, but it feels unsafe not to check for 0 ...
e.Current.Value.GreaterThanThresholdEU != 0D)
{
return true;
}
}
}
return false;
}
public static bool ValidateLevelTriggers(ref List<string> errors, TestTemplate currentTest)
{
var valid = true;
if (currentTest.LevelTriggerChannels.Any())
{
if (currentTest.HasMultipleSampleRates())
{
errors.Add(StringResources.EditTestSetupPage_LevelTriggersNotSupportedWithMultipleSampleRates);
}
//http://manuscript.dts.local/f/cases/36728/
//don't allow wake up with motion with level trigger <=5G
if (currentTest.WakeUpWithMotion)
{
if (currentTest.HasTSRAIRLevelTriggerLessThan5G())
{
errors.Add(StringResources.EditTestSetupPage_LevelTriggerToLowForWakeupOnMotion);
valid = false;
}
}
// 29403 TSRAIR needs some pre-trigger samples to accurately mark T0
if (currentTest.TSRAIRInActiveMode() && 0 == Math.Round(currentTest.PreTriggerSeconds, 4) && !currentTest.StartWithEvent)
{
errors.Add(StringResources.EditTestSetupPage_TSRAIRActiveLevelTriggerSetupsRequireSomePretrigger);
valid = false;
}
}
else if (DataModelSettings.TestsRequireLevelTriggers)
{
//FB14604: Config file option to require level triggers
errors.Add(StringResources.EditTestSetupPage_LevelTriggersRequired);
valid = false;
}
return valid;
}
public bool TSRAIRInActiveMode()
{
var hardware = GetHardware();
return TestHasTSRAIRDevices(hardware) &&
(RecordingMode == RecordingModes.Active ||
RecordingMode == RecordingModes.MultipleEventActive);
}
/// <summary>
/// Examines the hardware
/// </summary>
/// <returns>True if any DAS in a Test Setup contains a TSR AIR</returns>
public bool TestHasTSRAIRDevices(DASHardware[] hardware)
{
return Array.Exists(hardware, h => h.IsTSRAIR());
}
/// <summary>
/// Examines the hardware, sample rate, and channels in a Test Setup.
/// </summary>
/// <returns>True if any DAS in a Test Setup contains a TSR AIR, and the Sample Rate is > 500,
/// and the Test Setup has at least one TSR AIR High G channel.</returns>
public bool TSRAIRsSupportLevelTrigger()
{
var hardware = GetHardware();
return TestHasTSRAIRDevices(hardware) &&
Array.Exists(hardware, h => GetSampleRateForHardware(h) > DFConstantsAndEnums.TSR_AIR_HIGH_G_CUTOFF_RATE_SPS) &&
TestHasTSRAIRLevelTriggerChannel();
}
/// <summary>
/// Looks for TSR AIR High G channels in a Test Setup
/// </summary>
/// <returns>True if a Test Setup has at least one TSR AIR High G channel, False otherwise.</returns>
private bool TestHasTSRAIRLevelTriggerChannel()
{
foreach (var group in Groups)
{
foreach (var ch in ChannelsForGroup[group])
{
if (ch.Hardware.Contains(DFConstantsAndEnums.USER_CHANNEL_NAME_HIGHG))
{
return true;
}
}
}
return false;
}
public static bool ValidateTestLength(ref List<string> errors, ref List<string> warnings, TestTemplate test)
{
if (RecordingModeExtensions.IsACircularBufferMode(test.RecordingMode) || RecordingModeExtensions.IsARecorderMode(test.RecordingMode))
{
if ((test.PreTriggerSeconds + test.PostTriggerSeconds) < .1)
{
var msg = StringResources.TestSetupNoRecordingTimeError;
if (!errors.Contains(msg))
{
errors.Add(msg);
}
}
}
return true;
}
public static bool ValidateGraphs(ref List<string> errors, ref List<string> warnings, TestTemplate test)
{
var graphNames = new HashSet<string>();
foreach (var graph in test.TestGraphs)
{
if (graphNames.Contains(graph.GraphName.ToLower()))
{
var msg = $"{StringResources.TestSetupDuplicateGraphWarning} ({graph.GraphName})";
if (!warnings.Contains(msg))
{
warnings.Add(msg);
}
}
else { graphNames.Add(graph.GraphName.ToLower()); }
if (!graph.GroupChannels.Any())
{
var msg = string.Format(StringResources.TestSetupEmptyGraphWarning, graph.GraphName);
if (!warnings.Contains(msg))
{
warnings.Add(msg);
}
}
}
return true;
}
public static bool ValidateCalculatedChannels(ref List<string> errors, ref List<string> warnings, TestTemplate currentTest)
{
if (currentTest.CalculatedChannels.Count > 0 && !SerializedSettings.AllowCalculatedChannels)
{
//FB14483 "Should ignore validation/error in edit test setup save if Calculated Channel UI is not enabled"
warnings.Add(StringResources.EditTestSetupCC_TestCCButNoSystemCC);
return true;
}
var valid = true;
var names = new HashSet<string>();
var duplicates = new List<string>();
var channelLookup = new Dictionary<long, IGroupChannel>();
foreach (var group in currentTest.Groups)
{
var channels = currentTest.ChannelsForGroup[group];
foreach (var channel in channels)
{
if (channel.IsBlank() || channel.IsDisabled || !channel.SensorValid || !channel.HardwareValid)
{
continue;
}
channelLookup[channel.Id] = channel;
}
}
var hardwareLookup = currentTest.GetHardware().ToDictionary(h => h.DASId);
foreach (var cc in currentTest.CalculatedChannels)
{
if (cc.SupportsRealtime)
{
string serialNumber = null;
//verify all channels are on the same DAS
foreach (var id in cc.InputChannelIds)
{
//29782 If all Input Channels have been removed from a Calculated Channel,
//the channelid may be "", so don't cause an Exception if it is.
if (Int64.TryParse(id, out long lid))
{
if (channelLookup.ContainsKey(lid))
{
var channel = channelLookup[lid];
if (hardwareLookup.ContainsKey(channel.DASId))
{
if (string.IsNullOrWhiteSpace(serialNumber))
{
serialNumber = hardwareLookup[channel.DASId].SerialNumber;
}
else if (serialNumber != hardwareLookup[channel.DASId].SerialNumber)
{
errors.Add(string.Format(StringResources.TestTemplate_MultipleDAS,
cc.Name));
break;
}
}
}
}
else
{
//29782 cc.InputChannelIds.Length may be > 0, but one or more may
//be an empty string, so display this error because it won't get displayed below.
var err = string.Format(StringResources.EditTestSetupCC_NoInputChannels, cc.Name);
if (!errors.Contains(err))
{
errors.Add(err);
}
valid = false;
continue;
}
}
}
double sampleRate = double.NaN;
foreach (var channelid in cc.InputChannelIds)
{
//29782 If all Input Channels have been removed from a Calculated Channel,
//the channelid may be "", so don't cause an Exception if it is.
if (Int64.TryParse(channelid, out long lid))
{
if (channelLookup.ContainsKey(lid))
{
var channel = channelLookup[lid];
if (hardwareLookup.ContainsKey(channel.DASId))
{
var h = hardwareLookup[channel.DASId];
var hardwareRate = currentTest.GetSampleRateForHardware(h);
if (double.IsNaN(sampleRate))
{
sampleRate = hardwareRate;
}
else if (sampleRate != hardwareRate)
{
errors.Add(string.Format(StringResources.TestTemplate_CCMultipleSampleRates,
cc.Name));
break;
}
}
}
}
else
{
//29782 cc.InputChannelIds.Length may be > 0, but one or more may
//be an empty string, so display this error because it won't get displayed below.
var err = string.Format(StringResources.EditTestSetupCC_NoInputChannels, cc.Name);
if (!errors.Contains(err))
{
errors.Add(err);
}
valid = false;
continue;
}
}
if (cc.InputChannelIds.Length < 1)
{
if (!string.IsNullOrWhiteSpace(cc.Name))
{//don't bother warning if name ="", it's caught by a different warning right below and this one will be confusing
var err = string.Format(StringResources.EditTestSetupCC_NoInputChannels, cc.Name);
if (!errors.Contains(err))
{
errors.Add(err);
}
valid = false;
continue;
}
}
if (string.IsNullOrWhiteSpace(cc.Name))
{
var err = StringResources.EditTestSetupCC_NameRequired;
if (!errors.Contains(err))
{
errors.Add(err);
}
valid = false;
continue;
}
if (names.Contains(cc.Name))
{
if (!duplicates.Contains(cc.Name))
{
duplicates.Add(cc.Name);
}
}
names.Add(cc.Name);
if (cc.Name.Length >= 250)
{
var err = StringResources.EditTestSetupCC_NameLength;
if (!errors.Contains(err)) { errors.Add(err); }
valid = false;
continue;
}
switch (cc.Operation)
{
case Operations.IRTRACC3D:
case Operations.IRTRACC3D_ABDOMEN:
case Operations.IRTRACC3D_LOWERTHORAX:
if (cc.InputChannelIds.Length < 3)
{
valid = false;
if (!errors.Contains(StringResources.All3DIRTRACCChannelsRequired))
{
errors.Add(StringResources.All3DIRTRACCChannelsRequired);
}
}
var usedIds = new HashSet<string>();
foreach (var input in cc.InputChannelIds)
{
if (usedIds.Contains(input))
{
valid = false;
errors.Add(StringResources.RotationalPotsMustBeDifferent);
}
usedIds.Add(input);
}
break;
case Operations.Resultant:
case Operations.AVERAGE:
case Operations.SUM:
{
CheckUnits(cc, ref errors, channelLookup, currentTest, ref valid);
}
break;
case Operations.HIC:
{
CheckHIC(cc, ref errors, channelLookup, hardwareLookup, currentTest, ref valid);
}
break;
}
}
if (duplicates.Any())
{
if (!errors.Contains(StringResources.TestTemplate_CalculatedChannelDuplicateNames))
{
errors.Add(StringResources.TestTemplate_CalculatedChannelDuplicateNames);
valid = false;
}
}
return valid;
}
/// <summary>
/// examines HIC to see if the setup is valid
/// </summary>
/// <param name="cc"></param>
/// <param name="errors"></param>
/// <param name="channelLookup"></param>
/// <param name="hardwareLookup"></param>
/// <param name="currentTest"></param>
/// <param name="valid"></param>
private static void CheckHIC(CalculatedValueClass cc,
ref List<string> errors,
IReadOnlyDictionary<long, IGroupChannel> channelLookup,
IReadOnlyDictionary<int, DASHardware> hardwareLookup,
TestTemplate currentTest,
ref bool valid)
{
//must have 3 channels
//all channels must be "g" or msec
//all channels must have a hardware channel assigned?
if (3 != cc.InputChannelIds.Length)
{
errors.Add(string.Format(StringResources.TestTemplate_InvalidChannelsHIC, cc.Name));
return;
}
CheckHICChannel(cc.InputChannelIds[0], channelLookup, ref errors, cc.Name, StringResources.TestTemplate_InvalidAccelerationXHIC);
CheckHICChannel(cc.InputChannelIds[1], channelLookup, ref errors, cc.Name, StringResources.TestTemplate_InvalidAccelerationYHIC);
CheckHICChannel(cc.InputChannelIds[2], channelLookup, ref errors, cc.Name, StringResources.TestTemplate_InvalidAccelerationZHIC);
}
/// <summary>
/// examines whether the HIC channel is valid or not
/// </summary>
/// <param name="channelId"></param>
/// <param name="channelLookup"></param>
/// <param name="errors"></param>
/// <param name="ccName"></param>
/// <param name="channelErrorText"></param>
private static void CheckHICChannel(string channelId,
IReadOnlyDictionary<long, IGroupChannel> channelLookup,
ref List<string> errors, string ccName,
string channelErrorText)
{
if (long.TryParse(channelId, out var id))
{
if (!channelLookup.ContainsKey(id))
{
errors.Add(string.Format(channelErrorText, ccName));
return;
}
var channel = channelLookup[id];
var units = channel.Units.ToLower();
if (!Constants.ACCELERATION_UNITS.Contains(units))
{
errors.Add(string.Format(StringResources.TestTemplate_InvalidUnitsHIC, ccName,
channel.ToString()));
}
}
else
{
errors.Add(string.Format(channelErrorText, ccName));
return;
}
}
/// <summary>
/// checks that the units match for all input channels, if not records an error message and sets valid to false
/// </summary>
/// <param name="cc"></param>
/// <param name="errors"></param>
/// <param name="channelLookup"></param>
/// <param name="currentTest"></param>
/// <param name="valid"></param>
private static void CheckUnits(CalculatedValueClass cc, ref List<string> errors,
IDictionary<long, IGroupChannel> channelLookup, TestTemplate currentTest, ref bool valid)
{
var unit = string.Empty;
foreach (var ccid in cc.InputChannelIds)
{
if (string.IsNullOrWhiteSpace(ccid))
{
continue;
}
if (!long.TryParse(ccid, out var l))
{
var msg = string.Format(StringResources.CalculatedChannel_InvalidChannel,
cc.Name);
if (!errors.Contains(msg))
{
errors.Add(msg);
}
continue;
}
if (channelLookup.ContainsKey(l))
{
var sensor = currentTest.GetSensor(channelLookup[l]);
if (null == sensor) continue;
var sc = SensorCalibrationList.GetLatestCalibrationBySerialNumber(sensor);
if (null == sc)
{
continue;
}
if (string.IsNullOrEmpty(unit))
{
unit = sc.Records.Records[0].EngineeringUnits;
}
if (unit != sc.Records.Records[0].EngineeringUnits)
{
var error =
string.Format(
StringResources.EditTestSetupCC_UnitsDontMatch,
cc.Name);
if (!errors.Contains(error))
{
valid = false;
errors.Add(error);
} //it's an error but not fatal .. just warn
break;
}
}
else
{
valid = false;
var msg = string.Format(StringResources.CalculatedChannel_InvalidChannel,
cc.Name);
if (!errors.Contains(msg))
{
errors.Add(msg);
}
}
}
}
public static bool ValidateExports(ref List<string> errors, TestTemplate currentTest)
{
if (!currentTest.ViewExport || currentTest.ExportFormats != SupportedExportFormatBitFlags.none) return true;
errors.Add(StringResources.TestTEmplate_NoExportFormatsSelected);
return false;
}
public static bool ValidateUploadFolder(ref List<string> errors, TestTemplate currentTest)
{
//if we have a export ini file, we still allow a blank upload folder
if (!currentTest.UploadData || !string.IsNullOrWhiteSpace(currentTest.UploadFolder)) return true;
if (SerializedSettings.ExportINIFile.Length > 0) { return true; }
errors.Add(StringResources.TestTestTemplate_InvalidUploadPath);
return false;
}
private static bool ValidateAutoArmAllowability(ref List<string> errors, TestTemplate currentTest)
{
//17577 AutoArm Remove Auto-Arm from config file
//if (!currentTest.DoAutoArm /*|| Properties.Settings.Default.AllowAutoArm*/) return true;
//always allowed now
//errors.Add(StringResources.EditTestSetupInfo_AutoArmNotAllowed);
//return false;
return true;
}
private static bool ValidateStreamingAllowability(ref List<string> errors, TestTemplate currentTest)
{
if (!currentTest.DoStreaming || Defaults.GetUserSettingValueBool(ApplicationProperties.CurrentView.Id, PropertyEnums.PropertyIds.AllowStreamingModes)) return true;
errors.Add(StringResources.EditTestSetupInfo_StreamingNotAllowed);
return false;
}
private static bool ValidateStreamingSupported(ref List<string> errors, TestTemplate currentTest)
{
if (!currentTest.DoStreaming) return true;
//30429 Invalidate/fail sooner than Arm step if DAS doesn't have streaming capability/channel (TSR AIR may or may not)
//If using an older database, streamingChannelsForDAS may be non-null, but we'll catch 'em in
//the Hardware step of Run Test when we read the DISABLE_STREAMING_FEATURE system attribute.
var allChannels = currentTest.GetChannels();
var allDasSupportStreaming = true;
foreach (var das in currentTest.GetHardware())
{
if (das.DASTypeEnum == HardwareTypes.TSR_AIR || das.DASTypeEnum == HardwareTypes.TSR_AIR_RevB)
{
//var streamingChannelsForDAS = allChannels.Where(ch => ch.DASId == das.DASId && ch.IsStreamOut);
var streamingChannelsForDAS = das.Channels.Where(ch => ch.IsStreamOut);
if (streamingChannelsForDAS == null || !streamingChannelsForDAS.Any())
{
//The Test Setup wants to stream, but this TSR AIR doesn't support it
errors.Add(string.Format(StringResources.EditTestSetupInfo_StreamingNotAvailableOnDAS, das.SerialNumber, Environment.NewLine));
allDasSupportStreaming = false;
}
}
}
return allDasSupportStreaming;
}
/// <summary>
/// This function returns a warning if the value in System Settings | Sample packet size control that corresponds to the DAS sample rate is invalid.
/// The value is valid if:
/// 1. Delta time between packets is less than or equal to 100 ms (CH10 maximum limit of 0.100 seconds).
/// 2. Delta time between packets is greater than or equal to 2 ms (0.002 for S6A & S6ABR) or 4 ms (0.004 for TSR AIR) seconds.
/// 3. Packet size + 42 < 1480.
/// </summary>
/// <param name="warnings"></param>
/// <param name="currentTest"></param>
/// <returns></returns>
private static void ValidateSamplesPerPacket(ref List<string> warnings, TestTemplate currentTest)
{
const double minDeltaS6A = 0.002;
const double minDeltaTSRAIR = 0.004;
const int S6AChannels = 6; //SLICE6Air will always stream 6 channels, plus any in-use UART channels (if FW has Protocol Version 53)
const int AllS6ABRChannels = 6; //SLICE6Air-Br will always stream all 6 channels
if (!currentTest.DoStreaming) { return; }
//43623 We assume there is exactly one StreamOut channel per DAS
var streamOutChannels = currentTest.GetChannels().Where(ch => ch.IsStreamOut && ch.HardwareChannel != null).ToList();
foreach (var streamOutChannel in streamOutChannels)
{
var numChannelsToStream = 0;
var parentDAS = streamOutChannel.HardwareChannel.GetParentDAS();
switch (parentDAS.DASTypeEnum)
{
case HardwareTypes.SLICE6_AIR:
ValidateDelta(ref warnings, currentTest, parentDAS.SerialNumber, minDeltaS6A);
//43623 When support for streaming UART channels is available, only S6A (not S6A-BR) will do so,
//so consider the presence/absence of UART channels when setting numChannels for S6A.
var numUARTChannelsToStream = 0;
if (SLICE6AIR.IsUARTChannelStreamingSupported(parentDAS.ProtocolVersion))
{
numUARTChannelsToStream = currentTest.GetChannels().Count(ch => ch.IsUart &&
ch.HardwareChannel != null &&
ch.HardwareChannel.GetParentDAS().SerialNumber == parentDAS.SerialNumber);
}
numChannelsToStream = S6AChannels + numUARTChannelsToStream;
break;
case HardwareTypes.SLICE6_AIR_BR:
ValidateDelta(ref warnings, currentTest, parentDAS.SerialNumber, minDeltaS6A);
numChannelsToStream = AllS6ABRChannels;
break;
case HardwareTypes.TSR_AIR:
case HardwareTypes.TSR_AIR_RevB:
ValidateDelta(ref warnings, currentTest, parentDAS.SerialNumber, minDeltaTSRAIR);
//43623 TSR AIRs can have 3, 6, 9, or 11 channels - UART channels do not stream (yet)
numChannelsToStream = currentTest.GetChannels().Count(ch => ch.HardwareChannel != null &&
!ch.HardwareChannel.IsStreamOut &&
!ch.HardwareChannel.IsUart &&
ch.HardwareChannel.GetParentDAS().SerialNumber == parentDAS.SerialNumber);
break;
case HardwareTypes.SLICE6_AIR_TC:
ValidateDelta(ref warnings, currentTest, parentDAS.SerialNumber, minDeltaS6A);
numChannelsToStream = currentTest.GetChannels().Count(ch => ch.HardwareChannel != null &&
!ch.HardwareChannel.IsStreamOut &&
ch.HardwareChannel.GetParentDAS().SerialNumber == parentDAS.SerialNumber);
break;
default:
if (!warnings.Contains(StringResources.EditTestSetupInfo_PacketDeltaNotValidated))
{
warnings.Add(string.Format(StringResources.EditTestSetupInfo_PacketDeltaNotValidated, parentDAS.DASTypeEnum));
}
break;
}
ValidatePacketSize(ref warnings, streamOutChannel.StreamOutUDPProfile, numChannelsToStream, currentTest.DASSamplesPerPacketList[parentDAS.SerialNumber]);
}
}
/// <summary>
/// This function returns a warning if the time between packets is invalid.
///
/// Use ADC samples per packet divided by sample rate to calculate the time between packets (delta).
///
/// The delta is valid if it is greater than or equal to the minimum for the DAS type (0.002 seconds for S6A and S6ABR,
/// and 0.004 seconds for TSR AIR) and less than or equal to the maximum 0.100 seconds.
/// </summary>
/// <param name="warnings"></param>
/// <param name="currentTest"></param>
/// <param name="dasSerialNumber"></param>
/// <param name="minDelta"></param>
private static void ValidateDelta(ref List<string> warnings, TestTemplate currentTest, string dasSerialNumber, double minDelta)
{
var delta = currentTest.DASSamplesPerPacketList[dasSerialNumber] / currentTest.DASSampleRateList[dasSerialNumber];
var sb = new StringBuilder($"Packet delta is {delta}");
if ((delta < minDelta) && (!warnings.Contains(StringResources.EditTestSetupInfo_StreamingPacketsTooSmall)))
{
sb.Append($"; which is less than the minimum ({minDelta})");
warnings.Add(StringResources.EditTestSetupInfo_StreamingPacketsTooSmall);
}
else if ((delta > 0.100) && (!warnings.Contains(StringResources.EditTestSetupInfo_StreamingPacketsTooLarge)))
{
sb.Append($"; which is greater than the maximum (0.100)");
warnings.Add(StringResources.EditTestSetupInfo_StreamingPacketsTooLarge);
}
APILogger.Log(sb);
}
/// <summary>
/// This function returns a warning if the size of a packet exceeds the
/// maximum allowed (1480), or if an unrecognized stream profile is passed in.
/// </summary>
/// <param name="warnings"></param>
/// <param name="streamProfile"></param>
/// <param name="numChannelsToStream"></param>
/// <param name="adcSamplesPerPacket"></param>
private static void ValidatePacketSize(ref List<string> warnings, UDPStreamProfile streamProfile, int numChannelsToStream, int adcSamplesPerPacket)
{
var udpStreamProfilePacket = new UDPStreamProfilePacket();
var sb = new StringBuilder($"Packet size is ");
//Modify any field in the class that is not the default value
var packetSize = 0;
switch (streamProfile)
{
case UDPStreamProfile.CH10_ANALOG:
packetSize = Calculate_CH10_ANALOG_Size(numChannelsToStream, adcSamplesPerPacket, udpStreamProfilePacket);
break;
case UDPStreamProfile.CH10_PCM128_MM:
packetSize = Calculate_CH10_PCM128_MM_Size(numChannelsToStream, adcSamplesPerPacket, udpStreamProfilePacket);
break;
case UDPStreamProfile.CH10_ANALOG_2HDR:
packetSize = Calculate_CH10_ANALOG_2HDR_Size(numChannelsToStream, adcSamplesPerPacket, udpStreamProfilePacket);
break;
case UDPStreamProfile.CH10_PCM_128BIT_2HDR:
packetSize = Calculate_CH10_PCM_128BIT_2HDR_Size(numChannelsToStream, adcSamplesPerPacket, udpStreamProfilePacket);
break;
case UDPStreamProfile.TMNS_PCM_STANDARD:
packetSize = Calculate_TMNS_PCM_STANDARD_Size(numChannelsToStream, adcSamplesPerPacket, udpStreamProfilePacket);
break;
case UDPStreamProfile.TMNS_PCM_SUPERCOM:
packetSize = Calculate_TMNS_PCM_SUPERCOM_Size(numChannelsToStream, adcSamplesPerPacket);
break;
case UDPStreamProfile.IENA_PTYPE_STREAM:
packetSize = Calculate_IENA_PTYPE_STREAM_Size(numChannelsToStream, adcSamplesPerPacket, udpStreamProfilePacket);
break;
case UDPStreamProfile.CH10_MANUAL_CONFIG:
packetSize = Calculate_CH10_MANUAL_CONFIG_Size(numChannelsToStream, adcSamplesPerPacket);
break;
case UDPStreamProfile.UART_STREAM:
packetSize = Calculate_UART_STREAM_Size(numChannelsToStream, adcSamplesPerPacket);
break;
default:
if (!warnings.Contains(StringResources.EditTestSetupInfo_PacketSizeNotValidated))
{
sb.Append($"unknown because of invalid Stream Profile ({streamProfile})");
warnings.Add(string.Format(StringResources.EditTestSetupInfo_PacketSizeNotValidated, streamProfile));
APILogger.Log(sb);
}
return; //Don't break here, just return without calling ValidateStreamProfilePacketSize
}
ValidateStreamProfilePacketSize(packetSize, ref sb, ref warnings);
APILogger.Log(sb);
}
/// <summary>
/// Calculates the size of a CH10_ANALOG packet
/// </summary>
/// <param name="numChannelsToStream"></param>
/// <param name="adcSamplesPerPacket"></param>
/// <param name="udpStreamProfilePacket"></param>
/// <returns></returns>
private static int Calculate_CH10_ANALOG_Size(int numChannelsToStream, int adcSamplesPerPacket, UDPStreamProfilePacket udpStreamProfilePacket)
{
var packetSize = 0;
udpStreamProfilePacket.SecondTimeHeader = 0;
udpStreamProfilePacket.ChannelSpecificDataWord = 4;
packetSize = CalculateStreamProfilePacketSize(numChannelsToStream, adcSamplesPerPacket, udpStreamProfilePacket);
return packetSize;
}
/// <summary>
/// Calculates the size of a CH10_PCM128_MM packet
/// </summary>
/// <param name="numChannelsToStream"></param>
/// <param name="adcSamplesPerPacket"></param>
/// <param name="udpStreamProfilePacket"></param>
/// <returns></returns>
private static int Calculate_CH10_PCM128_MM_Size(int numChannelsToStream, int adcSamplesPerPacket, UDPStreamProfilePacket udpStreamProfilePacket)
{
var packetSize = 0;
udpStreamProfilePacket.PCMChannelSpecificDataWord = 4;
udpStreamProfilePacket.ChannelSpecificDataWord = 4;
packetSize = CalculateStreamProfilePacketSize(numChannelsToStream, adcSamplesPerPacket, udpStreamProfilePacket);
return packetSize;
}
/// <summary>
/// Calculates the size of a CH10_ANALOG_2HDR packet
/// </summary>
/// <param name="numChannelsToStream"></param>
/// <param name="adcSamplesPerPacket"></param>
/// <param name="udpStreamProfilePacket"></param>
/// <returns></returns>
private static int Calculate_CH10_ANALOG_2HDR_Size(int numChannelsToStream, int adcSamplesPerPacket, UDPStreamProfilePacket udpStreamProfilePacket)
{
var packetSize = 0;
udpStreamProfilePacket.SecondTimeHeader = 12;
udpStreamProfilePacket.ChannelSpecificDataWord = 4;
packetSize = CalculateStreamProfilePacketSize(numChannelsToStream, adcSamplesPerPacket, udpStreamProfilePacket);
return packetSize;
}
/// <summary>
/// Calculates the size of a CH10_PCM_128BIT_2HDR packet
/// </summary>
/// <param name="numChannelsToStream"></param>
/// <param name="adcSamplesPerPacket"></param>
/// <param name="udpStreamProfilePacket"></param>
/// <returns></returns>
private static int Calculate_CH10_PCM_128BIT_2HDR_Size(int numChannelsToStream, int adcSamplesPerPacket, UDPStreamProfilePacket udpStreamProfilePacket)
{
var packetSize = 0;
udpStreamProfilePacket.SecondTimeHeader = 12;
udpStreamProfilePacket.PCMChannelSpecificDataWord = 4;
udpStreamProfilePacket.ChannelSpecificDataWord = 4;
packetSize = CalculateStreamProfilePacketSize(numChannelsToStream, adcSamplesPerPacket, udpStreamProfilePacket);
return packetSize;
}
/// <summary>
/// Calculates the size of a TMNS_PCM_STANDARD packet
/// </summary>
/// <param name="numChannelsToStream"></param>
/// <param name="adcSamplesPerPacket"></param>
/// <param name="udpStreamProfilePacket"></param>
/// <returns></returns>
private static int Calculate_TMNS_PCM_STANDARD_Size(int numChannelsToStream, int adcSamplesPerPacket, UDPStreamProfilePacket udpStreamProfilePacket)
{
var packetSize = 0;
udpStreamProfilePacket.SecondTimeHeader = 12;
udpStreamProfilePacket.ChannelSpecificDataWord = 4;
udpStreamProfilePacket.PCMChannelSpecificDataWord = 4;
udpStreamProfilePacket.Id = 4;
udpStreamProfilePacket.SampleTime = 12;
packetSize = CalculateStreamProfilePacketSize(numChannelsToStream, adcSamplesPerPacket, udpStreamProfilePacket);
return packetSize;
}
/// <summary>
/// Calculates the size of a TMNS_PCM_SUPERCOM packet
/// </summary>
/// <param name="numChannelsToStream"></param>
/// <param name="adcSamplesPerPacket"></param>
/// <returns></returns>
private static int Calculate_TMNS_PCM_SUPERCOM_Size(int numChannelsToStream, int adcSamplesPerPacket)
{
var packetSize = 0;
const int packetHeader = 32;
const int payloadFactor = 2;
const int packageHeader = 12;
const int frameSync = 4;
const int sfidWord = 2;
const int stsWord = 2;
var payLoad = payloadFactor * numChannelsToStream;
var packagePayload = frameSync + sfidWord + stsWord + (payLoad * 4);
double quotient = adcSamplesPerPacket / 4D; //Must divide by a double
packetSize = (int)(packetHeader + ((packageHeader + packagePayload) * quotient));
return packetSize;
}
/// <summary>
/// Calculates the size of a IENA_PTYPE_STREAM packet
/// </summary>
/// <param name="numChannelsToStream"></param>
/// <param name="adcSamplesPerPacket"></param>
/// <param name="udpStreamProfilePacket"></param>
/// <returns></returns>
private static int Calculate_IENA_PTYPE_STREAM_Size(int numChannelsToStream, int adcSamplesPerPacket, UDPStreamProfilePacket udpStreamProfilePacket)
{
var packetSize = 0;
udpStreamProfilePacket.TransHeader = 14;
udpStreamProfilePacket.TimeHeader = 0;
udpStreamProfilePacket.SecondTimeHeader = 0;
udpStreamProfilePacket.ChannelSpecificDataWord = 0;
udpStreamProfilePacket.PCMChannelSpecificDataWord = 0;
udpStreamProfilePacket.Trailer = 2;
packetSize = CalculateStreamProfilePacketSize(numChannelsToStream, adcSamplesPerPacket, udpStreamProfilePacket);
return packetSize;
}
/// <summary>
/// Calculates the size of a CH10_MANUAL_CONFIG packet
/// </summary>
/// <param name="numChannelsToStream"></param>
/// <param name="adcSamplesPerPacket"></param>
/// <returns></returns>
private static int Calculate_CH10_MANUAL_CONFIG_Size(int numChannelsToStream, int adcSamplesPerPacket)
{
var packetSize = 0;
const int packetHeader = 32;
const int payloadFactor = 2;
var payload = payloadFactor * numChannelsToStream;
packetSize = packetHeader + (payload * adcSamplesPerPacket);
return packetSize;
}
/// <summary>
/// Calculates the size of a UART_STREAM packet
/// </summary>
/// <param name="numChannelsToStream"></param>
/// <param name="adcSamplesPerPacket"></param>
/// <returns></returns>
private static int Calculate_UART_STREAM_Size(int numChannelsToStream, int adcSamplesPerPacket)
{
var packetSize = 0;
const int packetHeader = 14;
const int payloadFactor = 2;
const int crc = 2;
var payload = payloadFactor * numChannelsToStream;
packetSize = packetHeader + crc + (payload * adcSamplesPerPacket);
return packetSize;
}
/// <summary>
/// This function calculates the size of a packet, based on the UDPStreamProfilePacket class
/// maximum allowed (1480).
/// </summary>
/// <param name="numChannelsToStream"></param>
/// <param name="adcSamplesPerPacket"></param>
/// <param name="udpStreamProfilePacket"></param>
private static int CalculateStreamProfilePacketSize(int numChannelsToStream, int adcSamplesPerPacket, UDPStreamProfilePacket udpStreamProfilePacket)
{
var packetSize = 0;
packetSize = udpStreamProfilePacket.TransHeader +
udpStreamProfilePacket.TimeHeader +
udpStreamProfilePacket.SecondTimeHeader +
udpStreamProfilePacket.ChannelSpecificDataWord +
((udpStreamProfilePacket.PCMChannelSpecificDataWord + udpStreamProfilePacket.Id + (udpStreamProfilePacket.PayloadFactor * numChannelsToStream)) * adcSamplesPerPacket) +
(udpStreamProfilePacket.SampleTime * (adcSamplesPerPacket - 1)) +
udpStreamProfilePacket.Trailer;
return packetSize;
}
/// <summary>
/// Determines whether a packet will be fragmented
/// </summary>
/// <param name="packetSize"></param>
/// <param name="sb"></param>
/// <param name="warnings"></param>
private static void ValidateStreamProfilePacketSize(int packetSize, ref StringBuilder sb, ref List<string> warnings)
{
const int additionalOverhead = 42;
const int maxPacketSize = 1480;
if (((packetSize + additionalOverhead) >= maxPacketSize) && !warnings.Contains(StringResources.EditTestSetupInfo_StreamingPacketsWillBeFragmented))
{
sb.Append($"; which is greater than the maximum ({maxPacketSize})");
warnings.Add(StringResources.EditTestSetupInfo_StreamingPacketsWillBeFragmented);
}
}
private static bool ValidateStreamingOutputAddresses(ref List<string> warnings, TestTemplate currentTest)
{
var streamOutChannels = currentTest.GetChannels().Where(ch => ch.IsStreamOut).ToList();
if (streamOutChannels.GroupBy(ch => ch.StreamOutUDPAddress.ToLower()).Select(ch => ch.First()).Count() != streamOutChannels.Count)
{
//we have multiple udp outs on the same address
//30048 Allow multiple udp outs, but display a warning
warnings.Add(StringResources.TestTemplate_UDPAddressesNotUnique);
}
return true;
}
private static bool ValidateStreamingProfiles(ref List<string> errors, TestTemplate currentTest)
{
var result = false;
try
{
result = true;
var availableProfiles = StreamOutputRecord.AvailableUDPStreamProfiles(DbOperations.GetConnectionDbVersion(),
StreamOutputSettingDefaults.GetStreamOutputSettingsDefault(ApplicationProperties.CurrentUser.Id).UseAdvancedUDPStreamProfiles);
var streamOutChannels = currentTest.GetChannels().Where(ch => ch.IsStreamOut).ToList();
foreach (var ch in streamOutChannels)
{
if ((ch.HardwareChannel != null) && !((DASHardware)ch.HardwareChannel.GetParentDAS()).SupportsStreamingProfile(ch.StreamOutUDPProfile))
{
errors.Add(string.Format(StringResources.TestTemplate_UnsupportedStreamingProfile, EnumDescriptionTypeConverter.GetEnumDescription(ch.StreamOutUDPProfile), ch.HardwareChannel.GetParentDAS().ToString()));
result = false;
}
if (!availableProfiles.Contains(ch.StreamOutUDPProfile))
{
if (!errors.Contains(StringResources.EditStreamOutputControl_EnableAdvancedUDPProfiles))
{
errors.Add(StringResources.EditStreamOutputControl_EnableAdvancedUDPProfiles);
}
var profileError = string.Format(StringResources.EditStreamOutputControl_InvalidUDPProfile, DTS.Common.Strings.Strings.ResourceManager.GetString(ch.StreamOutUDPProfile.GetEnumDescription()));
if (!errors.Contains(profileError))
{
errors.Add(profileError);
}
result = false;
}
ValidateStreamingProfiles(ref errors, ch.HardwareChannel?.GetParentDAS() ?? null);
}
}
catch (Exception ex)
{
//This is a model of how other validation functions can more gracefully avoid a misleading "Failure to update lock" error,
//and at the same time, give the user a clue as to where the validation failed.
var errorString = string.Format(StringResources.TestSetupValidationError, "ValidateStreamingProfiles");
var exceptionString = $"{errorString}: {ex.Message}";
APILogger.Log(exceptionString);
errors.Add(errorString);
result = false;
}
return result;
}
public static void ValidateStreamingProfiles(ref List<string> errors, IDASHardware hardware)
{
if (null == hardware) { return; }
var filterProfile = SerializedSettings.GetDefaultDSP();
var dasType = hardware.DASTypeEnum.ToString();
//look for matching dastype or empty string dastype, compare protocol version to hardware protocol version
var matchDasType = Array.Find(filterProfile.Restrictions, x => string.IsNullOrEmpty(x.DASType) || 0 == string.Compare(x.DASType, dasType, true));
if (null == matchDasType)
{
errors.Add(string.Format(StringResources.DASDoesntSupportFilterProfile, hardware.SerialNumber, filterProfile.DisplayString));
}
else if (matchDasType.ProtocolVersion > hardware.ProtocolVersion)
{
errors.Add(string.Format(StringResources.DASProtocolDoesntSupportFilterProfile, hardware.SerialNumber, filterProfile.DisplayString));
}
}
public static bool ValidateCommonStatusLine(ref List<string> errors, TestTemplate currentTest)
{
var sampleRatesAreMixed = currentTest.HasMultipleSampleRates();
if (!sampleRatesAreMixed || !currentTest.CommonLine) return true;
var hardware = currentTest.GetHardware();
//http://manuscript.dts.local/f/cases/44058/Unable-to-arm-multiple-das-with-different-sample-rates-due-to-Common-Status-Line-not-supported-error
//per EF if all devices are TSR AIR don't warn about this
if (Array.Exists(hardware, h => !h.IsTSRAIR()))
{
//This needs to be an error here so that the Test Setup will be saved in an incomplete state.
errors.Add(StringResources.EditObjectPageError_CommonStatusLineWithMultipleSampleRates);
return false;
}
return true;
}
public static bool ValidateSampleRates(ref List<string> errors, TestTemplate currentTest)
{
foreach (var comparableDas in currentTest.GetNonDistributorHardware())
{
var comparableSampleRate = currentTest.DASSampleRateList[comparableDas.SerialNumber];
foreach (var das in currentTest.GetNonDistributorHardware())
{
if ((currentTest.DASSampleRateList[das.SerialNumber] % comparableSampleRate != 0) &&
(comparableSampleRate % currentTest.DASSampleRateList[das.SerialNumber] != 0))
{
errors.Add(StringResources.EditTestSetupPage_Error_DASSampleRatesNotEvenlyDivisible);
return false;
}
}
}
return true;
}
private static bool AllowsZeroAAF(DASHardware hw)
{
switch (hw.DASTypeEnum)
{
case HardwareTypes.DIM:
case HardwareTypes.G5INDUMMY:
case HardwareTypes.G5VDS:
case HardwareTypes.SIM:
case HardwareTypes.TDAS_Pro_Rack:
case HardwareTypes.TDAS_LabRack:
case HardwareTypes.TOM:
return true;
default:
return false;
}
}
public static bool ValidateAAFilterRates(ref List<string> errors, ref List<string> warnings, TestTemplate currentTest, bool warnWhenRun)
{
var result = true;
var currentTestHardware = currentTest.GetHardware();
foreach (var hw in currentTestHardware)
{
if (!hw.IsTSRAIR() && CaresAboutAAF(hw))
{
if ((currentTest.DASAAFRateList[hw.SerialNumber] < 0) ||
//Allow TDAS hardware to run with 0 AAF
((currentTest.DASAAFRateList[hw.SerialNumber] == 0) && !AllowsZeroAAF(hw)) ||
(currentTest.DASAAFRateList[hw.SerialNumber] > Convert.ToDouble(hw.MaxAAFRate)))
{
//FB15759: the AAF we edited in is > what would be calculated, mark it error.
errors.Add(String.Format(StringResources.EditTestSetupPage_AAFilterRateOutOfRange, hw.ToString(), hw.MaxAAFRate.Replace(".00", ""), Environment.NewLine));
result = false;
}
//Don't allow an AAF rate higher than the Sample rate
if (currentTest.DASAAFRateList[hw.SerialNumber] > currentTest.DASSampleRateList[hw.SerialNumber])
{
if (warnWhenRun)
{
errors.Add(string.Format(StringResources.EditTestSetupPage_AAFilterRateGreaterThanSampleRate, hw.ToString(),
currentTest.DASAAFRateList[hw.SerialNumber].ToString(), currentTest.DASSampleRateList[hw.SerialNumber].ToString(), Environment.NewLine));
}
else
{
warnings.Add(String.Format(StringResources.EditTestSetupPage_AAFilterRateGreaterThanSampleRate, hw.ToString(),
currentTest.DASAAFRateList[hw.SerialNumber].ToString(), currentTest.DASSampleRateList[hw.SerialNumber].ToString(), Environment.NewLine));
}
result = false;
}
}
}
return result;
}
/// <summary>
/// returns true if the unit cares about AAF rates
/// 18029 Error about AAF during diagnostics and in edit test setup
/// </summary>
private static bool CaresAboutAAF(DASHardware dh)
{
return dh.CareAboutSampleRate;
}
private static void ValidateHardwareRecordingModes(RecordingModes mode, DASHardware[] hardware, ref List<string> errors, bool streaming)
{
foreach (var h in hardware)
{
//29609 At this point, test.RecordingMode may not yet have been set to the proper streaming value, so check test.DoStreaming also
if (h.IsNonDistributorHardware
&& !h.SupportsRecordingMode(mode)
&& !streaming)
{
errors.Add(string.Format(StringResources.TestTemplate_UnsupportedRecordingMode,
EnumDescriptionTypeConverter.GetEnumDescription(mode), h.ToString()));
}
}
}
private static void ValidateUARTRecordingMode(RecordingModes mode, ClockSyncProfile masterProfile, ClockSyncProfile slaveProfile, IGroupChannel[] channels,
ref List<string> errors, DASHardware[] hardware, string[] masterHardware, bool streaming,
TestSetupDefaults settings)
{
//UART recording mode checks
if (RecordingModeExtensions.IsAUartMode(mode))
{
if (!Array.Exists(channels, gc => gc.IsUart))
{
//is uart mode, has no uart channels
errors.Add(StringResources.TestTemplate_UARTModeNoChannels);
}
else if (!Array.Exists(hardware, h => h.SupportsRecordingMode(mode, true)))
{
errors.Add(StringResources.TestTemplate_UARTModeNoDAS);
}
}
//30479 don't warn if uart channel's being used for GPS clock sync
var uartChannelsNotSync = channels.Where(gc => gc.IsUart && !(masterProfile.ToString().Contains("GPS") && masterHardware.Contains(gc.HardwareChannel.GetParentDAS().SerialNumber))
&& !slaveProfile.ToString().Contains("GPS")).ToList();
var uartStreamOutChannels = channels.Where(gc => gc.IsStreamOut && gc.StreamOutUDPProfile == UDPStreamProfile.UART_STREAM).ToList();
if (!RecordingModeExtensions.IsAUartMode(mode) && uartChannelsNotSync.Any() &&
!RecordingModeExtensions.TestWillBeStreaming(mode, streaming))
{
//not a uart mode has uart channels that aren't being used for gps clock sync
errors.Add(StringResources.TestTemplate_UARTChannelsNoMode);
if (!settings?.AllowUARTRecordingModes ?? true)
{
//"allow uart modes" not enabled. tell user to do so
errors.Add(StringResources.TestTemplate_UARTModesNeedEnabling);
}
}
//uart channel configured, but not used for gps nor adc-to-uart
else if (RecordingModeExtensions.TestWillBeStreaming(mode, streaming) &&
uartChannelsNotSync.Exists(uart => !uartStreamOutChannels.Exists(usoc => uart.HardwareChannel.GetParentDAS().SerialNumber == usoc.HardwareChannel.GetParentDAS().SerialNumber)))
{
//streaming and a uart streamout channel doesn't have a corresponding uart config channel
errors.Add(StringResources.TestTemplate_UARTChannelsNoStream);
}
}
private static void ValidateStreamingModes(RecordingModes mode, bool streaming, IGroupChannel[] channels,
ref List<string> errors, DASHardware[] hardware, TestSetupDefaults settings)
{
//Streaming recording mode checks
//29609 At this point, test.RecordingMode may not yet have been set to the proper streaming value, so check test.DoStreaming also
if (RecordingModeExtensions.TestWillBeStreaming(mode, streaming) && !Array.Exists(channels, gc => gc.IsStreamOut))
{
//is streaming mode, but no settings channels
errors.Add(StringResources.TestTemplate_StreamOutModeNoChannels);
}
//29609 At this point, test.RecordingMode may not yet have been set to the proper streaming value, so check test.DoStreaming also
if (RecordingModeExtensions.TestWillBeStreaming(mode, streaming)
&& hardware.Where(das => Array.Exists(das.Channels, ch => ch.IsStreamOut)).Any(das => !Array.Exists(channels, gc => null != gc.HardwareChannel && gc.HardwareChannel.IsStreamOut && gc.HardwareChannel.GetParentDAS().SerialNumber == das.SerialNumber)))
{
//all included das with channels in test are required to have a stream out setting when we're in stream out mode
errors.Add(StringResources.TestTemplate_StreamOutModeDASWithNoSettings);
}
//30075 validate uart settings paired with streamout if streamout profile is adc-to-uart
if (RecordingModeExtensions.TestWillBeStreaming(mode, streaming) &&
hardware.Where(das => Array.Exists(das.Channels, ch => ch.IsStreamOut)).Any(das => Array.Exists(channels, gc => null != gc.HardwareChannel && gc.HardwareChannel.IsStreamOut && gc.StreamOutUDPProfile == UDPStreamProfile.UART_STREAM && gc.HardwareChannel.GetParentDAS().SerialNumber == das.SerialNumber) &&
!Array.Exists(channels, gc => null != gc.HardwareChannel && gc.HardwareChannel.IsUart && gc.HardwareChannel.GetParentDAS().SerialNumber == das.SerialNumber)))
{
//ADC-to-UART is chosen as the streamout profile, but no corresponding UART settings included
errors.Add(StringResources.TestTemplate_StreamOutUARTProfileNoUARTSettings);
}
//29609 At this point, test.RecordingMode may not yet have been set to the proper streaming value, so check test.DoStreaming also
if (!RecordingModeExtensions.TestWillBeStreaming(mode, streaming) && Array.Exists(channels, gc => gc.IsStreamOut))
{
//not a stream mode, but has settings channels
errors.Add(StringResources.TestTemplate_StreamOutChannelsNoMode);
if (!settings?.AllowStreamingModes ?? true)
{
//"allow streaming modes" not enabled. tell user to do so
errors.Add(StringResources.TestTemplate_StreamOutModesNeedEnabling);
}
}
//Streaming in HW check
if (hardware.Where(das => Array.Exists(das.Channels, ch => ch.IsStreamIn)).Any(das => !Array.Exists(channels, gc => null != gc.HardwareChannel && gc.HardwareChannel.IsStreamIn && gc.HardwareChannel.GetParentDAS().SerialNumber == das.SerialNumber)))
{
//if we include any hardware with streaming in channels those channels must be included in the test
errors.Add(StringResources.TestTemplate_StreamInDASWithNoSettings);
}
}
private static void ValidateAllowTSRAirRecordingMode(TestSetupDefaults settings, RecordingModes mode,
ref List<string> errors, string recordingModeText, DASHardware[] hardware)
{
//http://manuscript.dts.local/f/cases/29853/Warn-when-selected-recording-mode-is-not-available
//check AllowTSRAirRecordingModes against recording mode
//this is following the assumption that das recording modes are already checked above and we just need to check allowTSRAIRrecordingmodes
if (RecordingModeExtensions.IsTSRAIROnlyRecordingMode(mode) && !RecordingModeExtensions.IsTSRAirRecordingMode(mode))
{
//allow tsr air recording modes is off but this is a TSR AIR only recording mode, warn to turn it on
errors.Add(StringResources.TestTemplate_AllowTSRAirRecordingModesNotSet);
}
}
/// <summary>
/// returns false if there is a fatal error and the test setup should not be allowed to be saved
/// returns true if there are no issues preventing saving the test setup
/// adds an error if the test setup can be saved but there's an issue preventing running the test
/// adds a warning if the test setup can be saved and run, but there is an issue warranting notifying the user
/// 18490 stuck in preparing for data collection when you have a SPT attached and a test set for continuous recorder mode
/// </summary>
/// <param name="errors"></param>
/// <param name="warnings"></param>
/// <param name="test"></param>
/// <returns></returns>
public static bool ValidateRecordingModes(ref List<string> errors, ref List<string> warnings, TestTemplate test)
{
var hardware = test.GetHardware();
ValidateHardwareRecordingModes(test.RecordingMode, hardware, ref errors, test.DoStreaming);
var testChannels = test.GetChannels().ToArray();
var settings = TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id);
ValidateUARTRecordingMode(test.RecordingMode, test.ClockSyncProfileMaster, test.ClockSyncProfileSlave, testChannels, ref errors, hardware, test.DASClockMasterList.Where(kvp => true == kvp.Value).Select(kvp => kvp.Key).ToArray(), test.DoStreaming, settings);
ValidateStreamingModes(test.RecordingMode, test.DoStreaming, testChannels, ref errors, hardware, settings);
ValidateAllowTSRAirRecordingMode(settings, test.RecordingMode, ref errors, test.RecordingModeText, hardware);
return true;
}
public void SetClockSyncInputSlave(OutputClockSource source)
{
var selectedOutputMode = GetSelectedOutputPTPClockMode();
switch (source)
{
case OutputClockSource.PTP:
ClockSyncProfileSlave = "Auto" == selectedOutputMode
? ClockSyncProfile.Auto_E2E
: "1PPS" == selectedOutputMode
? ClockSyncProfile.Slave_E2E_PPS_OUT
: ClockSyncProfile.Slave_E2E;
break;
case OutputClockSource.None:
ClockSyncProfileSlave = "1PPS" == selectedOutputMode
? ClockSyncProfile.PPS_OUT
: ClockSyncProfile.None;
break;
}
}
public void SetClockSyncManualMaster(bool value)
{
ClockSyncProfileMaster = value ? ClockSyncProfile.Manual : ClockSyncProfile.None;
}
public void SetClockSyncManualSlave(bool value)
{
ClockSyncProfileSlave = value ? ClockSyncProfile.Manual : ClockSyncProfile.None;
}
public InputClockSource GetClockSyncInputSlave()
{
switch (ClockSyncProfileSlave)
{
case ClockSyncProfile.Slave_E2E:
case ClockSyncProfile.Slave_E2E_PPS_OUT:
case ClockSyncProfile.Auto_E2E:
return InputClockSource.PTP;
default: return InputClockSource.None;
}
}
public InputClockSource GetClockSyncProfileSlave()
{
return GetClockSyncProfileSlave(ClockSyncProfileSlave);
}
public static InputClockSource GetClockSyncProfileSlave(ClockSyncProfile clockSyncProfileSlave)
{
switch (clockSyncProfileSlave)
{
case ClockSyncProfile.PPS_OUT:
case ClockSyncProfile.Slave_E2E_PPS_OUT:
return InputClockSource.OnePPS;
case ClockSyncProfile.Slave_E2E:
return InputClockSource.PTP;
default:
return InputClockSource.None;
}
}
public void SetClockSyncOutputSlave(OutputClockSource source)
{
switch (source)
{
case OutputClockSource.OnePPS:
switch (ClockSyncProfileSlave)
{
case ClockSyncProfile.Slave_E2E:
ClockSyncProfileSlave = ClockSyncProfile.Slave_E2E_PPS_OUT;
break;
case ClockSyncProfile.None:
ClockSyncProfileSlave = ClockSyncProfile.PPS_OUT;
break;
}
break;
case OutputClockSource.None:
switch (ClockSyncProfileSlave)
{
case ClockSyncProfile.Slave_E2E_PPS_OUT:
ClockSyncProfileSlave = ClockSyncProfile.Slave_E2E;
break;
case ClockSyncProfile.PPS_OUT:
ClockSyncProfileSlave = ClockSyncProfile.None;
break;
}
break;
}
}
public string GetSelectedOutputPTPClockMode()
{
switch (ClockSyncProfileMaster)
{
case ClockSyncProfile.Master_E2E_IRIG:
case ClockSyncProfile.Master_E2E_IRIG_EXT_PPS:
case ClockSyncProfile.Master_E2E_GPS:
case ClockSyncProfile.Master_E2E_GPS_EXT_PPS:
case ClockSyncProfile.Master_E2E_EXT_PPS:
case ClockSyncProfile.Master_E2E:
case ClockSyncProfile.IRIG_Master_E2E_PPS_OUT:
case ClockSyncProfile.Master_E2E_PPS_OUT:
return "Master";
case ClockSyncProfile.Slave_E2E:
case ClockSyncProfile.Slave_E2E_PPS_OUT:
return "Slave";
case ClockSyncProfile.Auto_E2E:
return "Auto";
}
return "---";
}
public InputClockSource GetClockSyncInputMaster()
{
return GetClockSyncInputMaster(ClockSyncProfileMaster);
}
public static InputClockSource GetClockSyncInputMaster(ClockSyncProfile clockSyncProfileMaster)
{
var master = InputClockSource.None;
switch (clockSyncProfileMaster)
{
case ClockSyncProfile.IRIG:
case ClockSyncProfile.Master_E2E_IRIG:
case ClockSyncProfile.IRIG_PPS_OUT:
case ClockSyncProfile.IRIG_Master_E2E_PPS_OUT:
master = InputClockSource.IRIG;
break;
case ClockSyncProfile.IRIG_EXT_PPS:
case ClockSyncProfile.IRIG_EXT_PPS_PPS_OUT:
case ClockSyncProfile.Master_E2E_IRIG_EXT_PPS:
case ClockSyncProfile.IRIG_EXT_PPS_Master_E2E_PPS_OUT:
master = InputClockSource.IRIG_OnePPS;
break;
case ClockSyncProfile.GPS:
case ClockSyncProfile.GPS_PPS_OUT:
case ClockSyncProfile.Master_E2E_GPS:
case ClockSyncProfile.GPS_Master_E2E_PPS_OUT:
master = InputClockSource.GPS;
break;
case ClockSyncProfile.GPS_EXT_PPS:
case ClockSyncProfile.GPS_EXT_PPS_PPS_OUT:
case ClockSyncProfile.Master_E2E_GPS_EXT_PPS:
case ClockSyncProfile.GPS_EXT_PPS_Master_E2E_PPS_OUT:
master = InputClockSource.GPS_OnePPS;
break;
case ClockSyncProfile.EXT_PPS:
case ClockSyncProfile.EXT_PPS_PPS_OUT:
case ClockSyncProfile.Master_E2E_EXT_PPS:
case ClockSyncProfile.EXT_PPS_Master_E2E_PPS_OUT:
master = InputClockSource.OnePPS;
break;
}
return master;
}
public OutputClockSource GetClockSyncOutputMaster()
{
return GetClockSyncOutputMaster(ClockSyncProfileMaster);
}
public static OutputClockSource GetClockSyncOutputMaster(ClockSyncProfile clockSyncProfileMaster)
{
var master = OutputClockSource.None;
switch (clockSyncProfileMaster)
{
case ClockSyncProfile.Master_E2E_IRIG:
case ClockSyncProfile.Master_E2E_IRIG_EXT_PPS:
case ClockSyncProfile.Master_E2E_GPS:
case ClockSyncProfile.Master_E2E_GPS_EXT_PPS:
case ClockSyncProfile.Master_E2E_EXT_PPS:
case ClockSyncProfile.Master_E2E:
case ClockSyncProfile.Auto_E2E:
master = OutputClockSource.PTP;
break;
case ClockSyncProfile.Master_E2E_PPS_OUT:
case ClockSyncProfile.IRIG_Master_E2E_PPS_OUT:
case ClockSyncProfile.IRIG_EXT_PPS_Master_E2E_PPS_OUT:
case ClockSyncProfile.GPS_Master_E2E_PPS_OUT:
case ClockSyncProfile.GPS_EXT_PPS_Master_E2E_PPS_OUT:
case ClockSyncProfile.EXT_PPS_Master_E2E_PPS_OUT:
master = OutputClockSource.PTP_OnePPS;
break;
case ClockSyncProfile.PPS_OUT:
case ClockSyncProfile.IRIG_PPS_OUT:
case ClockSyncProfile.IRIG_EXT_PPS_PPS_OUT:
case ClockSyncProfile.GPS_PPS_OUT:
case ClockSyncProfile.GPS_EXT_PPS_PPS_OUT:
case ClockSyncProfile.EXT_PPS_PPS_OUT:
master = OutputClockSource.OnePPS;
break;
}
return master;
}
public void SetClockSyncInputMaster(InputClockSource source)
{
var clockSyncProfileMaster = ClockSyncProfileMaster;
SetClockSyncInputMaster(source, ref clockSyncProfileMaster);
ClockSyncProfileMaster = clockSyncProfileMaster;
}
public static void SetClockSyncInputMaster(InputClockSource source, ref ClockSyncProfile clockSyncProfileMaster)
{
var outputMaster = GetClockSyncOutputMaster(clockSyncProfileMaster);
switch (source)
{
case InputClockSource.GPS:
clockSyncProfileMaster = OutputClockSource.None == outputMaster
? ClockSyncProfile.GPS
: OutputClockSource.OnePPS == outputMaster
? ClockSyncProfile.GPS_PPS_OUT
: OutputClockSource.PTP_OnePPS == outputMaster
? ClockSyncProfile.GPS_Master_E2E_PPS_OUT
: ClockSyncProfile.Master_E2E_GPS;
break;
case InputClockSource.GPS_OnePPS:
clockSyncProfileMaster = OutputClockSource.None == outputMaster
? ClockSyncProfile.GPS_EXT_PPS
: OutputClockSource.OnePPS == outputMaster
? ClockSyncProfile.GPS_EXT_PPS_PPS_OUT
: OutputClockSource.PTP_OnePPS == outputMaster
? ClockSyncProfile.GPS_EXT_PPS_Master_E2E_PPS_OUT
: ClockSyncProfile.Master_E2E_GPS_EXT_PPS;
break;
case InputClockSource.IRIG:
clockSyncProfileMaster = OutputClockSource.None == outputMaster
? ClockSyncProfile.IRIG
: OutputClockSource.OnePPS == outputMaster
? ClockSyncProfile.IRIG_PPS_OUT
: OutputClockSource.PTP_OnePPS == outputMaster
? ClockSyncProfile.IRIG_Master_E2E_PPS_OUT
: ClockSyncProfile.Master_E2E_IRIG;
break;
case InputClockSource.IRIG_OnePPS:
clockSyncProfileMaster = OutputClockSource.None == outputMaster
? ClockSyncProfile.IRIG_EXT_PPS
: OutputClockSource.OnePPS == outputMaster
? ClockSyncProfile.IRIG_EXT_PPS_PPS_OUT
: OutputClockSource.PTP_OnePPS == outputMaster
? ClockSyncProfile.IRIG_EXT_PPS_Master_E2E_PPS_OUT
: ClockSyncProfile.Master_E2E_IRIG_EXT_PPS;
break;
case InputClockSource.OnePPS:
clockSyncProfileMaster = OutputClockSource.None == outputMaster
? ClockSyncProfile.EXT_PPS
: OutputClockSource.OnePPS == outputMaster
? ClockSyncProfile.EXT_PPS_PPS_OUT
: OutputClockSource.PTP_OnePPS == outputMaster
? ClockSyncProfile.EXT_PPS_Master_E2E_PPS_OUT
: ClockSyncProfile.Master_E2E_EXT_PPS;
break;
default:
clockSyncProfileMaster = OutputClockSource.None == outputMaster
? ClockSyncProfile.None
: OutputClockSource.OnePPS == outputMaster
? ClockSyncProfile.PPS_OUT
: OutputClockSource.PTP_OnePPS == outputMaster
? ClockSyncProfile.Master_E2E_PPS_OUT
: ClockSyncProfile.Master_E2E;
break;
}
}
public void SetClockSyncOutputMaster(OutputClockSource source)
{
var clockSyncProfileMaster = ClockSyncProfileMaster;
SetClockSyncOutputMaster(source, ref clockSyncProfileMaster);
ClockSyncProfileMaster = clockSyncProfileMaster;
}
public static void SetClockSyncOutputMaster(OutputClockSource source, ref ClockSyncProfile clockSyncProfileMaster)
{
switch (source)
{
case OutputClockSource.PTP:
switch (clockSyncProfileMaster)
{
case ClockSyncProfile.None:
case ClockSyncProfile.PPS_OUT:
case ClockSyncProfile.Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.Master_E2E;
break;
case ClockSyncProfile.IRIG:
case ClockSyncProfile.IRIG_PPS_OUT:
case ClockSyncProfile.IRIG_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.Master_E2E_IRIG;
break;
case ClockSyncProfile.GPS:
case ClockSyncProfile.GPS_PPS_OUT:
case ClockSyncProfile.GPS_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.Master_E2E_GPS;
break;
case ClockSyncProfile.EXT_PPS:
case ClockSyncProfile.EXT_PPS_PPS_OUT:
case ClockSyncProfile.EXT_PPS_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.Master_E2E_EXT_PPS;
break;
case ClockSyncProfile.IRIG_EXT_PPS:
case ClockSyncProfile.IRIG_EXT_PPS_PPS_OUT:
case ClockSyncProfile.IRIG_EXT_PPS_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.Master_E2E_IRIG_EXT_PPS;
break;
case ClockSyncProfile.GPS_EXT_PPS:
case ClockSyncProfile.GPS_EXT_PPS_PPS_OUT:
case ClockSyncProfile.GPS_EXT_PPS_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.Master_E2E_GPS_EXT_PPS;
break;
}
break;
case OutputClockSource.PTP_OnePPS:
switch (clockSyncProfileMaster)
{
case ClockSyncProfile.None:
case ClockSyncProfile.PPS_OUT:
case ClockSyncProfile.Master_E2E:
clockSyncProfileMaster = ClockSyncProfile.Master_E2E_PPS_OUT;
break;
case ClockSyncProfile.IRIG:
case ClockSyncProfile.Master_E2E_IRIG:
case ClockSyncProfile.IRIG_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.IRIG_Master_E2E_PPS_OUT;
break;
case ClockSyncProfile.GPS:
case ClockSyncProfile.Master_E2E_GPS:
case ClockSyncProfile.GPS_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.GPS_Master_E2E_PPS_OUT;
break;
case ClockSyncProfile.EXT_PPS:
case ClockSyncProfile.Master_E2E_EXT_PPS:
case ClockSyncProfile.EXT_PPS_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.EXT_PPS_Master_E2E_PPS_OUT;
break;
case ClockSyncProfile.IRIG_EXT_PPS:
case ClockSyncProfile.Master_E2E_IRIG_EXT_PPS:
case ClockSyncProfile.IRIG_EXT_PPS_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.IRIG_EXT_PPS_Master_E2E_PPS_OUT;
break;
case ClockSyncProfile.GPS_EXT_PPS:
case ClockSyncProfile.Master_E2E_GPS_EXT_PPS:
case ClockSyncProfile.GPS_EXT_PPS_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.GPS_EXT_PPS_Master_E2E_PPS_OUT;
break;
}
break;
case OutputClockSource.OnePPS:
switch (clockSyncProfileMaster)
{
case ClockSyncProfile.None:
case ClockSyncProfile.Master_E2E:
case ClockSyncProfile.Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.PPS_OUT;
break;
case ClockSyncProfile.IRIG:
case ClockSyncProfile.Master_E2E_IRIG:
case ClockSyncProfile.IRIG_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.IRIG_PPS_OUT;
break;
case ClockSyncProfile.GPS:
case ClockSyncProfile.Master_E2E_GPS:
case ClockSyncProfile.GPS_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.GPS_PPS_OUT;
break;
case ClockSyncProfile.EXT_PPS:
case ClockSyncProfile.Master_E2E_EXT_PPS:
case ClockSyncProfile.EXT_PPS_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.EXT_PPS_PPS_OUT;
break;
case ClockSyncProfile.IRIG_EXT_PPS:
case ClockSyncProfile.Master_E2E_IRIG_EXT_PPS:
case ClockSyncProfile.IRIG_EXT_PPS_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.IRIG_EXT_PPS_PPS_OUT;
break;
case ClockSyncProfile.GPS_EXT_PPS:
case ClockSyncProfile.Master_E2E_GPS_EXT_PPS:
case ClockSyncProfile.GPS_EXT_PPS_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.GPS_EXT_PPS_PPS_OUT;
break;
}
break;
case OutputClockSource.None:
switch (clockSyncProfileMaster)
{
case ClockSyncProfile.Master_E2E_IRIG:
case ClockSyncProfile.IRIG_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.IRIG;
break;
case ClockSyncProfile.Master_E2E_GPS:
case ClockSyncProfile.GPS_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.GPS;
break;
case ClockSyncProfile.Master_E2E_EXT_PPS:
case ClockSyncProfile.EXT_PPS_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.EXT_PPS;
break;
case ClockSyncProfile.Master_E2E_IRIG_EXT_PPS:
case ClockSyncProfile.IRIG_EXT_PPS_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.IRIG_EXT_PPS;
break;
case ClockSyncProfile.Master_E2E_GPS_EXT_PPS:
case ClockSyncProfile.GPS_EXT_PPS_Master_E2E_PPS_OUT:
clockSyncProfileMaster = ClockSyncProfile.GPS_EXT_PPS;
break;
default:
clockSyncProfileMaster = ClockSyncProfile.None;
break;
}
break;
}
}
public static DTS.Common.Classes.ClockSync.ClockSyncProfile GetGrandMasterClock(TestTemplate test)
{
var collection = DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.GetCollection();
switch(test.ClockSyncProfileMaster)
{
case ClockSyncProfile.Master_E2E: return collection.GetClockSyncProfile(DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.NONE_NAME);
case ClockSyncProfile.Master_E2E_IRIG: return collection.GetClockSyncProfile(DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.IRIGB_NAME);
case ClockSyncProfile.Master_E2E_EXT_PPS: return collection.GetClockSyncProfile(DTS.Common.Classes.ClockSync.ClockSyncProfileCollection._1PPS_NAME);
case ClockSyncProfile.Master_E2E_IRIG_EXT_PPS: return collection.GetClockSyncProfile(DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.IRIGB1PPS_NAME);
case ClockSyncProfile.Master_E2E_GPS_EXT_PPS: return collection.GetClockSyncProfile(DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.GPS1PPS_NAME);
case ClockSyncProfile.Slave_E2E_Master_E2E_OUT: return collection.GetClockSyncProfile(DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.PTPIEEE1588_NAME);
}
if ( test.ClockSyncProfileMaster != ClockSyncProfile.None) { return collection.GetClockSyncProfile(DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.NONE_NAME); }
switch(test.ClockSyncProfileSlave)
{
case ClockSyncProfile.Slave_E2E: return collection.GetClockSyncProfile(DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.PTPIEEE1588_NAME);
case ClockSyncProfile.GPS_EXT_PPS: return collection.GetClockSyncProfile(DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.GPS1PPS_NAME);
case ClockSyncProfile.IRIG_EXT_PPS: return collection.GetClockSyncProfile(DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.IRIGB1PPS_NAME);
case ClockSyncProfile.EXT_PPS: return collection.GetClockSyncProfile(DTS.Common.Classes.ClockSync.ClockSyncProfileCollection._1PPS_NAME);
case ClockSyncProfile.IRIG: return collection.GetClockSyncProfile(DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.IRIGB_NAME);
case ClockSyncProfile.None:
default:
return collection.GetClockSyncProfile(DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.NONE_NAME);
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Code Smell", "S3458:Empty \"case\" clauses that fall through to the \"default\" should be omitted", Justification = "clearer")]
public static void SetGrandMasterClock(DTS.Common.Classes.ClockSync.ClockSyncProfile profile, TestTemplate test)
{
var hardware = test.GetHardware();
var masterFound = Array.Exists(hardware, x => test.DASClockMasterList.ContainsKey(x.SerialNumber) && test.DASClockMasterList[x.SerialNumber]);
switch (profile.ProfileName)
{
case DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.PTPIEEE1588_NAME:
SetGrandMasterClockPTP(test, masterFound);
break;
case DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.IRIGB1PPS_NAME:
SetGrandMasterClockIRIG1PPS(test, masterFound);
break;
case DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.GPS1PPS_NAME:
SetGrandMasterClockGPS1PPS(test, masterFound);
break;
case DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.IRIGB_NAME:
SetGrandMasterClockIRIGB(test, masterFound);
break;
case DTS.Common.Classes.ClockSync.ClockSyncProfileCollection._1PPS_NAME:
SetGrandMasterClock1PPS(test, masterFound);
break;
case DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.NONE_NAME:
default:
SetGrandMasterClockNone(test, masterFound);
break;
}
}
private static void SetGrandMasterClock1PPS(TestTemplate test, bool masterFound)
{
if (masterFound)
{
test.ClockSyncProfileMaster = ClockSyncProfile.Master_E2E_EXT_PPS;
test.ClockSyncProfileSlave = ClockSyncProfile.Slave_E2E;
}
else
{
test.ClockSyncProfileMaster = ClockSyncProfile.None;
test.ClockSyncProfileSlave = ClockSyncProfile.EXT_PPS;
}
}
private static void SetGrandMasterClockIRIGB(TestTemplate test, bool masterFound)
{
if (masterFound)
{
test.ClockSyncProfileMaster = ClockSyncProfile.Master_E2E_IRIG;
test.ClockSyncProfileSlave = ClockSyncProfile.Slave_E2E;
}
else
{
test.ClockSyncProfileMaster = ClockSyncProfile.None;
test.ClockSyncProfileSlave = ClockSyncProfile.IRIG;
}
}
private static void SetGrandMasterClockGPS1PPS(TestTemplate test, bool masterFound)
{
if (masterFound)
{
test.ClockSyncProfileMaster = ClockSyncProfile.Master_E2E_GPS_EXT_PPS;
test.ClockSyncProfileSlave = ClockSyncProfile.Slave_E2E;
}
else
{
test.ClockSyncProfileMaster = ClockSyncProfile.None;
test.ClockSyncProfileSlave = ClockSyncProfile.GPS_EXT_PPS;
}
}
private static void SetGrandMasterClockIRIG1PPS(TestTemplate test, bool masterFound)
{
if (masterFound)
{
test.ClockSyncProfileMaster = ClockSyncProfile.Master_E2E_IRIG_EXT_PPS;
test.ClockSyncProfileSlave = ClockSyncProfile.Slave_E2E;
}
else
{
test.ClockSyncProfileMaster = ClockSyncProfile.None;
test.ClockSyncProfileSlave = ClockSyncProfile.IRIG_EXT_PPS;
}
}
private static void SetGrandMasterClockPTP(TestTemplate test, bool masterFound)
{
if (masterFound)
{
//note this is an invalid configuration!
test.ClockSyncProfileMaster = ClockSyncProfile.Slave_E2E_Master_E2E_OUT;
test.ClockSyncProfileSlave = ClockSyncProfile.Slave_E2E;
}
else
{
test.ClockSyncProfileMaster = ClockSyncProfile.None;
test.ClockSyncProfileSlave = ClockSyncProfile.Slave_E2E;
}
}
private static void SetGrandMasterClockNone(TestTemplate test, bool masterFound)
{
if (masterFound)
{
test.ClockSyncProfileMaster = ClockSyncProfile.Master_E2E;
test.ClockSyncProfileSlave = ClockSyncProfile.Slave_E2E;
}
else
{
test.ClockSyncProfileMaster = ClockSyncProfile.None;
test.ClockSyncProfileSlave = ClockSyncProfile.None;
}
}
private static bool ValidateClockSyncProfiles(ref List<string> errors, TestTemplate currentTest)
{
var result = true;
try
{
if (null == currentTest) { return true; }
//nothing more to check
if (currentTest.ClockSyncProfileMaster == ClockSyncProfile.None)
{
return true;
}
var hardware = currentTest.GetHardware();
foreach (var h in hardware)
{
if (null == h) { continue; }
if (h.IsConfigurableClockSync)
{
if (null == currentTest.DASClockMasterList) { continue; }
if (!currentTest.DASClockMasterList.ContainsKey(h.SerialNumber))
{
currentTest.DASClockMasterList[h.SerialNumber] = false;
}
switch (currentTest.DASClockMasterList[h.SerialNumber])
{
case true:
if (!h.SupportsClockSyncProfile(currentTest.ClockSyncProfileMaster, true))
{
errors.Add(string.Format(StringResources.TestTemplate_UnsupportedClockSyncProfile, EnumDescriptionTypeConverter.GetEnumDescription(currentTest.ClockSyncProfileMaster), h.ToString()));
result = false;
}
break;
case false:
if (!h.SupportsClockSyncProfile(currentTest.ClockSyncProfileSlave, false))
{
errors.Add(string.Format(StringResources.TestTemplate_UnsupportedClockSyncProfile, EnumDescriptionTypeConverter.GetEnumDescription(currentTest.ClockSyncProfileSlave), h.ToString()));
result = false;
}
break;
}
}
}
//check to see that there's a master clock specified if a master clock profile is set (with the exception of PTP which should only run with no master ...)
var grandMasterType = TestTemplate.GetGrandMasterClock(currentTest);
var hasMaster = currentTest.DASClockMasterList.Any(x => x.Value && Array.Exists(hardware, y => y.SerialNumber == x.Key));
if (currentTest.ClockSyncProfileMaster != ClockSyncProfile.None && grandMasterType.ProfileName != DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.PTPIEEE1588_NAME)
{
var masterDAS = currentTest.DASClockMasterList.Where(kvp => kvp.Value);
if (!masterDAS.Any())
{
errors.Add(StringResources.NoClockMasters);
return false;
}
}
if (hasMaster && grandMasterType.ProfileName == DTS.Common.Classes.ClockSync.ClockSyncProfileCollection.PTPIEEE1588_NAME)
{
errors.Add(StringResources.InvalidClockSync_PTPMaster);
return false;
}
//30487 GPS only clock sync option should be removed
if (currentTest.ClockSyncProfileMaster.ToString().Contains("GPS") && !currentTest.ClockSyncProfileMaster.ToString().Contains("EXT_PPS"))
{
errors.Add(StringResources.TestTemplate_GPSOnlyNotSufficientAdd1PPS);
var defaultCSP = TestSetupDefaults.GetUserSettingValueString(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.DefaultClockSyncProfileMaster);
if (defaultCSP.Contains("GPS") && !defaultCSP.Contains("EXT_PPS"))
{
errors.Add(StringResources.TestTemplate_GPSOnlyTestSetupDefault);
}
result = false;
}
//30479 make sure GPS clock masters have UART configured
if (currentTest.ClockSyncProfileMaster.ToString().Contains("GPS"))
{
var masterDASSerials = currentTest.DASClockMasterList.Where(kvp => kvp.Value).Select(kvp => kvp.Key).ToList();
var uartChannelDASSerials = currentTest.GetChannels().Where(gc => gc.IsUart).Select(gc => gc.HardwareChannel.GetParentDAS().SerialNumber).ToList();
if (masterDASSerials.Exists(serial => !uartChannelDASSerials.Contains(serial)))
{
// a master clock das reliant on GPS doesn't have a uart channel configured in the test
errors.Add(StringResources.TestTemplate_GPSMasterButMissingUARTConfig);
result = false;
}
}
// 29842 LTS concerns for 1PPS out
// if we've selected a 1PPS out profile, check whether we're using a central db and if so, see if it's new enough to support 1PPS out
// database version is probably cached, otherwise will cache on this get
if ((Constants.OnePPSOutProfiles.Contains(currentTest.ClockSyncProfileMaster) || Constants.OnePPSOutProfiles.Contains(currentTest.ClockSyncProfileSlave)) &&
DbOperations._usingCentralizedDB &&
DbOperations.GetConnectionDbVersion() < Constants.ONEPPS_OUT_DB_VERSION)
{
errors.Add(string.Format(StringResources.TestTemplate_UnsupportedClockSyncProfileLTS, Constants.ONEPPS_OUT_DB_VERSION, DbOperations.GetConnectionDbVersion()));
result = false;
}
}
catch (Exception ex)
{
//This is a model of how other validation functions can more gracefully avoid a misleading "Failure to update lock" error,
//and at the same time, give the user a clue as to where the validation failed.
var errorString = string.Format(StringResources.TestSetupValidationError, "ValidateClockSyncProfiles");
var exceptionString = $"{errorString}: {ex.Message}";
APILogger.Log(exceptionString);
}
return result;
}
public static bool ValidateStorageSpace(ref List<string> errors, TestTemplate currentTest)
{
var bStorageSpaceValid = true;
var preTriggerSeconds = currentTest.PreTriggerSeconds;
var postTriggerSeconds = currentTest.PostTriggerSeconds;
var das = new List<DASHardware>();
foreach (var to in currentTest.TestObjects)
{
foreach (var h in to.Hardware)
{
if (!das.Contains(h)) { das.Add(h); }
}
}
foreach (var to in currentTest.AddedGroups)
{
foreach (var h in to.Hardware)
{
if (!das.Contains(h)) { das.Add(h); }
}
}
var allHardware = currentTest.GetHardware();
foreach (var h in allHardware)
{
if (!das.Contains(h)) { das.Add(h); }
}
var maxSampleRate = 0.0D;
foreach (var d in das)
{
var rate = currentTest.GetSampleRateForHardware(d);
if (rate > maxSampleRate)
{
maxSampleRate = rate;
}
}
var secondsToRecord = preTriggerSeconds + postTriggerSeconds;
var sampleClocksToRecord = (ulong)(secondsToRecord * maxSampleRate + 1);
foreach (var d in das)
{
if (d.IsSLICETC()) continue; //SLICE6 AIR-Tc does not record, it only streams, so no need to validate storage space.
double maxSampleClockTicks = GetMaxSampleClockTicks(d, currentTest.RecordingMode);
if (maxSampleClockTicks <= 0) continue;
if (sampleClocksToRecord <= maxSampleClockTicks) continue;
bStorageSpaceValid = false;
int maxSeconds = (int)(maxSampleClockTicks / maxSampleRate);
errors.Add(string.Format(StringResources.TestTemplate_InsufficientMemory, d.SerialNumber, maxSeconds));
}
return bStorageSpaceValid;
}
/// <summary>
/// returns the max sample clock ticks expected to be recordable on a particular das
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
private static double GetMaxSampleClockTicks(DASHardware d, RecordingModes recordingMode)
{
double sampleClockTicks = d.GetMaxMemoryLong();
if (RecordingModeExtensions.IsAUartMode(recordingMode))
{
//SLICE UART recording modes currently require reserving half of the memory for UART
//http://manuscript.dts.local/f/cases/30489/Max-event-length-not-taking-UART-into-consideration-with-UART-recording-modes
//indeterminate what this means for multiple event modes
return sampleClockTicks / 2D;
}
return sampleClockTicks;
}
public static bool ValidateROI(ref List<string> errors, TestTemplate currentTest)
{
if (currentTest.RegionsOfInterest.GroupBy(roi => roi.Suffix).Select(roi => roi.First()).Count() != currentTest.RegionsOfInterest.Count)
{
//we have multiple suffixes
errors.Add(StringResources.TestTemplate_ROISuffixNotUnique);
return false;
}
return true;
}
#endregion Validate
#region PropertyChanged
public override event PropertyChangedEventHandler PropertyChanged;
public override void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void _customers_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(TestTemplateTags.AllCustomers.ToString());
}
private void _testEngineers_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(TestTemplateTags.AllTestEngineers.ToString());
}
void _labs_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(TestTemplateTags.AllLabs.ToString());
}
#endregion PropertyChanged
/// <summary>
/// holds test settings that don't have individual db columns
/// </summary>
private TestSettingDictionary _settings;
/// <summary>
/// gets a serialized version of the settings table
/// </summary>
/// <returns></returns>
public string GetSettings()
{
return _settings.ToSerializeString();
}
/// <summary>
/// loads values from a serialized string into the settings table
/// </summary>
/// <param name="s"></param>
public void LoadSettings(string s)
{
_settings.LoadSettings(s);
}
/// <summary>
/// constructs a settings table with some default values
/// default values can then have their values changed by LoadSettings if we are loading from a db
/// </summary>
/// <returns></returns>
private static TestSettingDictionary CreateSettingsDictionary(TestSetupDefaults usersettings)
{
var settings = new TestSettingDictionary();
settings.SetValue(new TestSetting(TestSettingsEnum.ArmCheckListStep, usersettings.DefaultArmCheckListStep.ToString(), usersettings.DefaultArmCheckListStep.ToString()));
settings.SetValue(new TestSetting(TestSettingsEnum.CheckListBatteryVoltageCheck, usersettings.DefaultCheckListBatteryVoltageCheck.ToString(), usersettings.DefaultCheckListBatteryVoltageCheck.ToString()));
settings.SetValue(new TestSetting(TestSettingsEnum.CheckListInputVoltageCheck, usersettings.DefaultCheckListInputVoltageCheck.ToString(), usersettings.DefaultCheckListInputVoltageCheck.ToString()));
settings.SetValue(new TestSetting(TestSettingsEnum.CheckListSensorIDCheck, usersettings.DefaultCheckListSensorIdCheck.ToString(), usersettings.DefaultCheckListSensorIdCheck.ToString()));
settings.SetValue(new TestSetting(TestSettingsEnum.CheckListSquibResistanceCheck, usersettings.DefaultCheckListSquibResistanceCheck.ToString(), usersettings.DefaultCheckListSquibResistanceCheck.ToString()));
settings.SetValue(new TestSetting(TestSettingsEnum.CheckListTriggerStartCheck, usersettings.DefaultCheckListTriggerStartCheck.ToString(), usersettings.DefaultCheckListTriggerStartCheck.ToString()));
settings.SetValue(new TestSetting(TestSettingsEnum.CheckListTiltSensorCheck, usersettings.DefaultCheckListTiltSensorCheck.ToString(), usersettings.DefaultCheckListTiltSensorCheck.ToString()));
settings.SetValue(new TestSetting(TestSettingsEnum.CheckListTemperatureCheck, usersettings.DefaultCheckListTemperatureCheck.ToString(), usersettings.DefaultCheckListTemperatureCheck.ToString()));
settings.SetValue(new TestSetting(TestSettingsEnum.CheckListMustPass, usersettings.DefaultChecklistMustPass.ToString(), usersettings.DefaultChecklistMustPass.ToString()));
var sValue = Convert.ToInt32(usersettings.DefaultTestExcitationWarmupSeconds * 1000D).ToString(CultureInfo.InvariantCulture);
settings.SetValue(new TestSetting(TestSettingsEnum.EW, sValue, sValue));
//initialize here
return settings;
}
/// <summary>
/// ExcitationWarmupTimeMS is the public available property for test excitation warmup, it is a max of every object warmup time and the test
/// warmup time itself. For now they are always going to be the same, which is okay, but we have the flexibility to change that in
/// the future if desired.
/// This property is just the test excitation warmup time itself without the consideration of test object excitation times.
/// </summary>
private int ExcitationWarmup
{
get => Convert.ToInt32(GetSetting(TestSettingsEnum.EW), CultureInfo.InvariantCulture);
set => SetSetting(TestSettingsEnum.EW, value.ToString(CultureInfo.InvariantCulture));
}
public bool CheckListTriggerStartCheck
{
get => Convert.ToBoolean(GetSetting(TestSettingsEnum.CheckListTriggerStartCheck));
set => SetSetting(TestSettingsEnum.CheckListTriggerStartCheck, value.ToString());
}
private string GetSetting(TestSettingsEnum setting)
{
var defaultValue = GetDefaultValue(setting);
var s = _settings.GetValue(setting, defaultValue);
switch (setting)
{
case TestSettingsEnum.ArmCheckListStep:
case TestSettingsEnum.CheckListBatteryVoltageCheck:
case TestSettingsEnum.CheckListInputVoltageCheck:
case TestSettingsEnum.CheckListSensorIDCheck:
case TestSettingsEnum.CheckListSquibResistanceCheck:
case TestSettingsEnum.CheckListTriggerStartCheck:
case TestSettingsEnum.CheckListTiltSensorCheck:
case TestSettingsEnum.CheckListTemperatureCheck:
case TestSettingsEnum.CheckListClockSyncCheck:
case TestSettingsEnum.CheckListMustPass:
{
return bool.TryParse(s, out var b) ? b.ToString() : defaultValue;
}
case TestSettingsEnum.EW:
{
return int.TryParse(s, out var i) ? i.ToString(CultureInfo.InvariantCulture) : defaultValue;
}
default: throw new NotSupportedException("unsupported: " + setting);
}
}
private static string GetDefaultValue(TestSettingsEnum setting)
{
switch (setting)
{
case TestSettingsEnum.ArmCheckListStep: return Defaults.GetUserSettingValueBool(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.DefaultArmCheckListStep).ToString();
case TestSettingsEnum.CheckListBatteryVoltageCheck: return Defaults.GetUserSettingValueBool(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.DefaultCheckListBatteryVoltageCheck).ToString();
case TestSettingsEnum.CheckListInputVoltageCheck: return Defaults.GetUserSettingValueBool(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.DefaultCheckListInputVoltageCheck).ToString();
case TestSettingsEnum.CheckListSensorIDCheck: return Defaults.GetUserSettingValueBool(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.DefaultCheckListSensorIdCheck).ToString();
case TestSettingsEnum.CheckListSquibResistanceCheck: return Defaults.GetUserSettingValueBool(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.DefaultCheckListSquibResistanceCheck).ToString();
case TestSettingsEnum.CheckListMustPass: return Defaults.GetUserSettingValueBool(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.DefaultCheckListMustPass).ToString();
case TestSettingsEnum.CheckListTriggerStartCheck: return Defaults.GetUserSettingValueBool(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.DefaultCheckListTriggerStartCheck).ToString();
case TestSettingsEnum.CheckListTiltSensorCheck: return Defaults.GetUserSettingValueBool(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.DefaultCheckListTiltSensorCheck).ToString();
case TestSettingsEnum.CheckListTemperatureCheck: return Defaults.GetUserSettingValueBool(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.DefaultCheckListTemperatureCheck).ToString();
case TestSettingsEnum.CheckListClockSyncCheck: return Defaults.GetUserSettingValueBool(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.DefaultCheckListClockSyncCheck).ToString();
case TestSettingsEnum.EW: return Convert.ToInt32(Defaults.GetUserSettingValueDouble(ApplicationProperties.CurrentUser.Id, PropertyEnums.PropertyIds.DefaultTestExcitationWarmupSeconds)).ToString(CultureInfo.InvariantCulture);
default: return true.ToString();
}
}
private void SetSetting(TestSettingsEnum setting, string value)
{
_settings.SetValue(setting, value);
OnPropertyChanged(setting.ToString());
}
public HardwareChannel GetHardwareChannel(int absoluteNumber)
{
lock (HardwareChannelLookupLock)
{
if (null == _absoluteNumberToHardwareChannel)
{
PopulateHardwareChannelLookup();
}
return _absoluteNumberToHardwareChannel[absoluteNumber];
}
}
private string _currentSearchTerm = "";
public void FilterTestObjects(string term)
{
_currentSearchTerm = term;
OnPropertyChanged(TestTemplateTags.AvailableTestObjects.ToString());
}
//TODO: Review functionality - should not be a property
public DTS.Common.ISO.TestObject[] AvailableTestObjects => throw new NotImplementedException();
private void PopulateHardwareChannelLookup()
{
var absoluteChannelNumber = 0;
_absoluteNumberToHardwareChannel = new Dictionary<int, HardwareChannel>();
_dasChannelNumberToAbsoluteNumber = new Dictionary<string, int>();
foreach (var to in TestObjects)
{
foreach (var das in to.Hardware)
{
var dasChannelNumber = 0;
var channels = das.Channels;
if (null == channels || !channels.Any()) continue;
foreach (var channel in channels)
{
_absoluteNumberToHardwareChannel.Add(absoluteChannelNumber, channel);
var key = $"{das.SerialNumber}_{dasChannelNumber}";
if (!_dasChannelNumberToAbsoluteNumber.ContainsKey(key)) { _dasChannelNumberToAbsoluteNumber.Add(key, absoluteChannelNumber); }
dasChannelNumber++;
absoluteChannelNumber++;
}
}
}
}
public int GetAbsoluteNumber(string serial, int dasChannelNumber)
{
lock (HardwareChannelLookupLock)
{
if (null == _dasChannelNumberToAbsoluteNumber) { PopulateHardwareChannelLookup(); }
}
return _dasChannelNumberToAbsoluteNumber[$"{serial}_{dasChannelNumber}"];
}
public double GetPreTriggerSeconds(string serial)
{
return _dasSettings.ContainsKey(serial) ? _dasSettings[serial].PreTriggerSeconds : PreTriggerSeconds;
}
public void SetPreTriggerSeconds(DASHardware h, double d)
{
if (!_dasSettings.ContainsKey(h.SerialNumber)) { _dasSettings.Add(h.SerialNumber, CreateDASSettings(h)); }
_dasSettings[h.SerialNumber].PreTriggerSeconds = d;
}
public double GetPostTriggerSeconds(string serial)
{
return _dasSettings.ContainsKey(serial) ? _dasSettings[serial].PostTriggerSeconds : PostTriggerSeconds;
}
public void SetPostTriggerSeconds(DASHardware h, double d)
{
if (!_dasSettings.ContainsKey(h.SerialNumber)) { _dasSettings.Add(h.SerialNumber, CreateDASSettings(h)); }
_dasSettings[h.SerialNumber].PostTriggerSeconds = d;
}
public void SetTestObjects(bool bMemoryOnly, TestTestObject[] value)
{
if (!bMemoryOnly)
{
MarkIsCompleteUnchecked();
}
SetProperty(ref _testObjects, new List<TestTestObject>(value), TestTemplateTags.TestObjects.ToString());
OnPropertyChanged(TestTemplateTags.AvailableTestObjects.ToString()); //No longer needed for added test objects combobox, but still used to update the remaining list of available test objects
OnPropertyChanged(TestTemplateTags.AllTestObjects.ToString());
OnPropertyChanged("TestObjectsAndAddedGroups");
}
public void SetAddedGroupsMemoryOnly(TestTestObject[] value)
{
SetProperty(ref _addedGroups, new List<TestTestObject>(value), TestTemplateTags.SysBuiltTestObjectTypes.ToString());
OnPropertyChanged(TestTemplateTags.AllTestObjects.ToString());//check this
OnPropertyChanged("TestObjectsAndAddedGroups");
OnPropertyChanged(TestTemplateTags.TestObjectsAndAddedGroups.ToString());
}
public void AddTestObject(TestObject to, int excitationWarmupMs, double targetSampleRate, string testobject, string position, int displayOrder)
{
if (null != to)
{
var tto = new TestTestObject(to)
{
ExcitationWarmupTimeMS = excitationWarmupMs,
TargetSampleRate = targetSampleRate,
DisplayOrder = displayOrder
};
tto.SetPosition(position);
tto.SetTestObject(testobject);
//if this is the NON ISO group (which is created by default), the replace the original NONE group ...
if (tto.SerialNumberOrOriginalSerialNumber == NON_ISO_INTERNAL_GROUP_NAME)
{
var index = -1;
for (var i = 0; i < TestObjectsAndAddedGroupsList.Count; i++)
{
if (TestObjectsAndAddedGroupsList[i].SerialNumberOrOriginalSerialNumber != NON_ISO_INTERNAL_GROUP_NAME) continue;
index = i;
break;
}
if (index >= 0)
{
TestObjectsAndAddedGroupsList.RemoveAt(index);
}
index = -1;
for (var i = 0; i < _testObjects.Count; i++)
{
if (_testObjects[i].SerialNumberOrOriginalSerialNumber != NON_ISO_INTERNAL_GROUP_NAME) continue;
index = i;
break;
}
if (index >= 0)
{
_testObjects.RemoveAt(index);
}
}
_testObjects.Add(tto);
TestObjectsAndAddedGroupsList.Add(tto);
OnPropertyChanged(TestTemplateTags.TestObjects.ToString());
OnPropertyChanged(TestTemplateTags.DefaultNumberRealtimeGraphs.ToString());
}
TestObjectsAndAddedGroupsList.Sort();
}
public void AddAddedGroup(TestObject to, string testobject, string position, string testSetupName, int displayOrder)
{
if (null == to) return;
var tto = new TestTestObject(to);
tto.SetPosition(position);
tto.SetTestObject(testobject);
tto.SerialNumberConverted = tto.SerialNumber.Remove(0, testSetupName.Length + 1);
tto.TestSetupName = testSetupName;
tto.DisplayOrder = displayOrder;
_addedGroups.Add(tto);
TestObjectsAndAddedGroupsList.Add(tto);
TestObjectsAndAddedGroupsList.Sort();
OnPropertyChanged(TestTemplateTags.DefaultNumberRealtimeGraphs.ToString());
}
public int GetNumberOfRealtimeSupportedChannels()
{
var count = 0;
foreach (var to in TestObjects)
{
var isoto = to.GetISOTestObject();
count += isoto.AllChannels.Where(ch => ch.Required && !string.IsNullOrWhiteSpace(ch.SensorSerialNumber)).Select(ch => GetSensor(ch.SensorSerialNumber, to.SerialNumber, ch.Name)).Where(sd => null != sd).Count(sd => !sd.IsDigitalInput() && !sd.IsDigitalOutput() && !sd.IsSquib());
}
foreach (var to in AddedGroups)
{
var isoto = to.GetISOTestObject();
count += isoto.AllChannels.Where(ch => ch.Required && !string.IsNullOrWhiteSpace(ch.SensorSerialNumber)).Select(ch => GetSensor(ch.SensorSerialNumber, to.SerialNumber, ch.Name)).Where(sd => null != sd).Count(sd => !sd.IsDigitalInput() && !sd.IsDigitalOutput() && !sd.IsSquib());
}
if (0 == count) { count = MAX_REALTIME_CHANNELS; }
return count;
}
public override string ToString()
{
return $"{Name} ({Description})";
}
private readonly Dictionary<string, DTS.Slice.Control.Event.Module.Channel> _channelLookup = new Dictionary<string, DTS.Slice.Control.Event.Module.Channel>();
public void AddChannelLookup(string key, DTS.Slice.Control.Event.Module.Channel value)
{
lock (ChannelLookupLock)
{
_channelLookup[key] = value;
}
}
private readonly Dictionary<string, bool> _sessionOpen = new Dictionary<string, bool>();
public HardwareChannel GetChannel(int index)
{
return ChannelCount > index ? _hardwareChannelsInOrder[index] : null;
}
public DTS.Slice.Control.Event.Module.Channel GetPersistentChannel(int index)
{
lock (CountLock)
{
if (_channelKeysInOrder.Count < 1)
{
foreach (var to in TestObjects)
{
foreach (var hardware in to.Hardware)
{
var dasChannelNumber = 0;
foreach (var channel in hardware.Channels)
{
if (null != channel.Sensor)
{
var key = $"{hardware.SerialNumber}_{dasChannelNumber}";
if (!_channelKeysInOrder.Contains(key))
{
_channelKeysInOrder.Add(key);
_hardwareChannelsInOrder.Add(channel);
}
}
dasChannelNumber++;
}
}
}
}
}
lock (ChannelLookupLock)
{
if (!_sessionOpen.ContainsKey(_channelKeysInOrder[index])) { _sessionOpen.Add(_channelKeysInOrder[index], true); }
return _channelLookup[_channelKeysInOrder[index]];
}
}
/// <summary>
/// for some reason it seems custom and lab details are held in two different areas, in meta deta and in the custom/lab detail objects
/// this function merely synchronizes the meta data with the objects
/// </summary>
public void SynchronizeTestMetaData()
{
var fields = Enum.GetValues(typeof(TestSetupMetaData.Fields)).Cast<TestSetupMetaData.Fields>().ToArray();
var customerOverride = CustomerOverride;
var engineerOverride = EngineerOverride;
var labOverride = LabOverride;
foreach (var field in fields)
{
string sValue;
switch (field)
{
case TestSetupMetaData.Fields.CustName:
sValue = (null == CustomerDetails) ? string.Empty : CustomerDetails.Name;
//the name of the record? we don't let you set this currently in the UI in Edit TestSetup ... so no override available
break;
case TestSetupMetaData.Fields.CustomerCostUnit:
sValue = (null == CustomerDetails) ? Constants.NoValue : CustomerDetails.CustomerCostUnit;
if (null != customerOverride) { sValue = customerOverride.CustomerCostUnit; }
break;
case TestSetupMetaData.Fields.CustomerName:
sValue = (null == CustomerDetails) ? string.Empty : CustomerDetails.CustomerName;
if (null != customerOverride) { sValue = customerOverride.CustomerName; }
break;
case TestSetupMetaData.Fields.CustomerOrderNumber:
sValue = (null == CustomerDetails) ? Constants.NoValue : CustomerDetails.CustomerOrderNumber;
if (null != customerOverride) { sValue = customerOverride.CustomerOrderNumber; }
break;
case TestSetupMetaData.Fields.CustomerProjectReferenceNumber:
sValue = (null == CustomerDetails) ? Constants.NoValue : CustomerDetails.ProjectRefNumber;
if (null != customerOverride) { sValue = customerOverride.ProjectRefNumber; }
break;
case TestSetupMetaData.Fields.TEName:
sValue = (null == TestEngineerDetails) ? string.Empty : TestEngineerDetails.Name;
//the record name? we don't let you change this in the UI currently, so there's no override for it ...
break;
case TestSetupMetaData.Fields.TestEngineerEmail:
sValue = (null == TestEngineerDetails) ? Constants.NoValue : TestEngineerDetails.TestEngineerEmail;
if (null != engineerOverride) { sValue = engineerOverride.TestEngineerEmail; }
break;
case TestSetupMetaData.Fields.TestEngineerFax:
sValue = (null == TestEngineerDetails) ? Constants.NoValue : TestEngineerDetails.TestEngineerFax;
if (null != engineerOverride) { sValue = engineerOverride.TestEngineerFax; }
break;
case TestSetupMetaData.Fields.TestEngineerName:
sValue = (null == TestEngineerDetails) ? Constants.NoValue : TestEngineerDetails.TestEngineerName;
if (null != engineerOverride) { sValue = engineerOverride.TestEngineerName; }
break;
case TestSetupMetaData.Fields.TestEngineerPhone:
sValue = (null == TestEngineerDetails) ? Constants.NoValue : TestEngineerDetails.TestEngineerPhone;
if (null != engineerOverride) { sValue = engineerOverride.TestEngineerPhone; }
break;
case TestSetupMetaData.Fields.CustomerTestReferenceNumber:
sValue = (null == CustomerDetails) ? string.Empty : CustomerDetails.CustomerTestRefNumber;
if (null != customerOverride) { sValue = customerOverride.CustomerTestRefNumber; }
break;
case TestSetupMetaData.Fields.LabName:
sValue = (null == LabDetails) ? string.Empty : LabDetails.Name;
//we don't expose the name in the UI in edit test setup, so no override value available
break;
case TestSetupMetaData.Fields.LaboratoryContactEmail:
sValue = (null == LabDetails) ? Constants.NoValue : LabDetails.LabratoryContactEmail;
if (null != labOverride) { sValue = labOverride.LabratoryContactEmail; }
break;
case TestSetupMetaData.Fields.LaboratoryContactFax:
sValue = (null == LabDetails) ? Constants.NoValue : LabDetails.LabratoryContactFax;
if (null != labOverride) { sValue = labOverride.LabratoryContactFax; }
break;
case TestSetupMetaData.Fields.LaboratoryContactName:
sValue = (null == LabDetails) ? Constants.NoValue : LabDetails.LabratoryContactName;
if (null != labOverride) { sValue = labOverride.LabratoryContactName; }
break;
case TestSetupMetaData.Fields.LaboratoryContactPhone:
sValue = (null == LabDetails) ? Constants.NoValue : LabDetails.LabratoryContactPhone;
if (null != labOverride) { sValue = labOverride.LabratoryContactPhone; }
break;
case TestSetupMetaData.Fields.LaboratoryName:
sValue = (null == LabDetails) ? string.Empty : LabDetails.LabratoryName;
if (null != labOverride) { sValue = labOverride.LabratoryName; }
break;
case TestSetupMetaData.Fields.LaboratoryTestReferenceNumber:
sValue = (null == LabDetails) ? string.Empty : LabDetails.LabratoryTestRefNumber;
if (null != labOverride) { sValue = labOverride.LabratoryTestRefNumber; }
break;
case TestSetupMetaData.Fields.LaboratoryProjectReferenceNumber:
sValue = (null == LabDetails) ? string.Empty : LabDetails.LabratoryProjectRefNumber;
if (null != labOverride) { sValue = labOverride.LabratoryProjectRefNumber; }
break;
default:
continue;
}
if (null != sValue)
{
GetTestMetaData().SetPropertyValue(field, sValue);
}
}
}
#region CalculatedChannels
public void RemoveCalculatedChannel(CalculatedValueClass ch)
{
CalculatedChannels.Remove(ch);
}
public void AddCalculatedChannel(CalculatedValueClass ch)
{
CalculatedChannels.Add(ch);
}
public void UpdateCalculatedChannelId(string[] names, int[] newIds)
{
var lookup = new Dictionary<string, CalculatedValueClass>();
foreach (var cc in CalculatedChannels)
{
lookup[cc.Name] = cc;
}
for (var i = 0; i < names.Length && i < newIds.Length; i++)
{
if (lookup.ContainsKey(names[i])) { lookup[names[i]].Id = newIds[i]; }
}
}
public void UpdateCalculatedChannelId(string name, int newId)
{
foreach (var cc in CalculatedChannels)
{
if (cc.Name == name) { cc.Id = newId; break; }
}
}
public void RemoveImpossibleCalculatedChannels()
{
if (0 == CalculatedChannels.Count) { return; }
var objects = new List<TestObject>(TestObjects);
objects.AddRange(AddedGroups);
var groupChannelIdLookup = new Dictionary<string, bool>();
foreach (var to in objects.ToArray())
{
var isoto = to.GetISOTestObject();
foreach (var ch in isoto.AllChannels)
{
if (ch.Required && !string.IsNullOrWhiteSpace(ch.SensorSerialNumber))
{
groupChannelIdLookup[ch.GetId()] = true;
}
}
}
var invalidCCs = new List<CalculatedValueClass>();
foreach (var cc in CalculatedChannels)
{
if (!cc.IsValid(groupChannelIdLookup))
{
invalidCCs.Add(cc);
}
}
foreach (var invalid in invalidCCs)
{
RemoveCalculatedChannel(invalid);
}
}
public void ReplaceCalculatedChannel(Dictionary<string, string> oldIdToNewIdLookup)
{
foreach (var cc in CalculatedChannels)
{
for (var i = 0; i < cc.InputChannelIds.Length; i++)
{
if (oldIdToNewIdLookup.ContainsKey(cc.InputChannelIds[i]))
{
cc.ReplaceInputChannelIdAtIndex(i, oldIdToNewIdLookup[cc.InputChannelIds[i]]);
}
}
}
}
public void RenameCalculatedChannels(string oldName, string newName)
{
foreach (var cc in CalculatedChannels)
{
for (var i = 0; i < cc.InputChannelIds.Length; i++)
{
if (cc.InputChannelIds[i].StartsWith(oldName))
{
cc.ReplaceInputChannelIdAtIndex(i, cc.InputChannelIds[i].Replace(oldName, newName));
}
}
if (cc.TestSetupName.StartsWith(oldName))
{
cc.TestSetupName = cc.TestSetupName.Replace(oldName, newName);
}
}
}
#endregion CalculatedChannels
public void ReplaceROIChannels(List<IGroupChannel> newGroupChannelList)
{
foreach (var roi in RegionsOfInterest)
{
roi.ChannelIds = new long[roi.ChannelNames.Length];
}
foreach (var newGroupChannel in newGroupChannelList)
{
//If a new channel is in any of the ROIs, update the Id
foreach (var roi in RegionsOfInterest)
{
var channelIndex = 0;
//foreach (var channelGUID in roi.ChannelGuids)
foreach (var channelId in roi.ChannelIds)
//foreach (var channelName in roi.ChannelNames)
{
var hardwareChannelName = string.Empty;
if ((newGroupChannel.HardwareChannel != null) && newGroupChannel.HardwareChannel.IsTSRAIR)
{
var hyphenIndex = newGroupChannel.HardwareChannel.ModuleSerialNumber.IndexOf('-');
hardwareChannelName = GenerateEmbeddedChannelName(newGroupChannel.HardwareChannel.ModuleSerialNumber.Substring(0, hyphenIndex),
$"\\{newGroupChannel.GetChannelName(SerializedSettings.ISOViewMode)}");
}
else
{
var channelName = newGroupChannel.Sensor == SensorConstants.VOLTAGE_INPUT
? newGroupChannel.Sensor
: newGroupChannel.SensorData.SerialNumber;
var newGroupChannelHardware = string.Empty;
if (string.IsNullOrWhiteSpace(newGroupChannel.Hardware) && (newGroupChannel.DASId > 0) && newGroupChannel.DASChannelIndex >= 0)
{
var dasList = GetHardwareFromDb();
foreach (var das in dasList)
{
if (das.DASId == newGroupChannel.DASId)
{
if (newGroupChannel.IsSquib)
{
newGroupChannelHardware = $"[{das.SerialNumber}] {StringResources.ChannelPrefix_Squib}{((newGroupChannel.DASChannelIndex * 2) + 1).ToString("00")}";
}
else
{
newGroupChannelHardware = $"[{das.SerialNumber}] {StringResources.ChannelPrefix_Other}{(newGroupChannel.DASChannelIndex + 1).ToString("00")}";
}
break; //Found the DAS we were looking for
}
}
}
else
{
newGroupChannelHardware = $"{newGroupChannel.Hardware}";
}
hardwareChannelName = $"{newGroupChannelHardware}\\{channelName}";
}
//FB 44012 Remove Assigned By ID from channel name so it would find the mathc correctly
if (roi.ChannelNames[channelIndex] == RegionOfInterest.RemoveAssignedByIDFromHardwareString(hardwareChannelName))
{
roi.ChannelIds[channelIndex] = newGroupChannel.Id;
break; //now check the other ROI(s)
}
channelIndex++;
}
}
}
}
public void SetHardwareOverride(string hid, bool bAdd)
{
HardwareOverrides[hid] = new HardwareInclusionInstruction(hid, bAdd ? HardwareInclusionInstruction.Actions.Add : HardwareInclusionInstruction.Actions.Remove);
OnPropertyChanged(TestTemplateTags.HardwareOverrides.ToString());
}
/// <summary>
/// takes a dynamic group in the test and replaces it with a snapshot of the static group
/// also updates calculated channels and level trigger channels
/// 15400 Group Push/Pull should allow the LT to be preserved in the Test Setup regardless of push/pull
/// </summary>
/// <param name="_updateGroup"></param>
/// <param name="staticGroup"></param>
public void UpdateDynamicGroupFromStaticGroup(IGroup _updateGroup, IGroup staticGroup)
{
//before we remove the old group we need to make sure we cache all the channels belonging to the old group
//so that when we add the new group we can restore connections to level triggers and calculated channels
//15400 Group Push/Pull should allow the LT to be preserved in the Test Setup regardless of push/pull
//now there's a stored procedure sp_CompareGroups which determines the difference-ness in groups
//but we'll have to do it in code here
var testSetupChannelIdToGroupChannelId = GetIGroupChannelIdToIGroupChannel();
var channelNameToChannelId = new Dictionary<string, long>();
var viewMode = SerializedSettings.ISOViewMode;
using (var eChannel = testSetupChannelIdToGroupChannelId.GetEnumerator())
{
while (eChannel.MoveNext())
{
channelNameToChannelId[eChannel.Current.Value.GetChannelName(viewMode)] =
eChannel.Current.Key;
}
}
var oldListCalculatedChannels = CalculatedChannels.ToArray();
//Remove the old embedded Group
RemoveGroup(_updateGroup);
//Add the static Group as the new embedded Group
staticGroup.LoadHardware();
if (!Groups.Any())
{
staticGroup.DisplayOrder = 1;
}
else
{
staticGroup.DisplayOrder = 1 + Groups.Max(g => g.DisplayOrder);
}
var allHardware = DASHardwareList.GetAllHardware();
var lookup = new Dictionary<int, IDASHardware>();
foreach (var h in allHardware) { lookup[h.DASId] = h; }
var hardware = staticGroup.IncludedHardware;
foreach (var id in hardware)
{
AddHardware(id, lookup);
}
ClearHardware();
var channelDefaults = DbOperations.GetChannelSettingDefaults();
staticGroup.StaticGroupId = _updateGroup.StaticGroupId;
AddGroup(staticGroup, channelDefaults);
var channelsForGroup = ChannelsForGroup[staticGroup].ToList();
channelsForGroup.Sort();
var channels = GetChannels();
//build a lookup of old channel to new channel for channels in the group that got pulled
// 15400 Group Push/Pull should allow the LT to be preserved in the Test Setup regardless of push/pull
var oldChannelToNewChannel = new Dictionary<IGroupChannel, IGroupChannel>();
foreach (var channel in channelsForGroup)
{
channels.Remove(channel);
if (channel.IsBlank())
{
continue;
}
var name = channel.GetChannelName(viewMode);
//find the old channel using the channel name
if (!channelNameToChannelId.ContainsKey(name))
{
//didn't find it, either it's a new channel or was renamed somewhere
continue;
}
var old = testSetupChannelIdToGroupChannelId[channelNameToChannelId[name]];
//18096 Don't overwrite any embedded Group IsoCode characters with '?' from static Group
var sb = new StringBuilder(channel.IsoCode);
for (int i = 0; i < 16; i++)
{
if (channel.IsoCode[i] == '?')
{
sb[i] = old.IsoCode[i];
}
}
channel.IsoCode = sb.ToString();
oldChannelToNewChannel[old] = channel;
}
var errors = new List<string>();
//now correct level trigger and calculated channels
// 15400 Group Push/Pull should allow the LT to be preserved in the Test Setup regardless of push/pull
CorrectCalculatedChannels(oldChannelToNewChannel, testSetupChannelIdToGroupChannelId, ref errors, viewMode);
CorrectLevelTriggerChannels(oldChannelToNewChannel);
//if there are any errors, push them to the user
if (errors.Any())
{
var eventAggregator = ContainerLocator.Container.Resolve<IEventAggregator>();
eventAggregator.GetEvent<PageErrorEvent>().Publish(new PageErrorArg(errors.ToArray(), null));
}
var insertPoint = -1;
for (var i = channels.Count - 1; i >= 0; i--)
{
if (channels[i].IsBlank())
{
continue;
}
insertPoint = i + 1;
break;
}
if (insertPoint < 0)
{
insertPoint = 0;
}
for (var i = channelsForGroup.Count - 1; i >= 0; i--)
{
channels.Insert(insertPoint, channelsForGroup[i]);
}
for (var i = 0; i < channels.Count; i++)
{
if (channels[i].IsBlank())
{
continue;
}
channels[i].TestSetupOrder = 1 + i;
}
//Re-evaluate the Position and Test Object since they may have changed
staticGroup.DeterminePositionAndTestObject(channelsForGroup.ToArray());
MoveGroupToDisplayOrder(staticGroup, _updateGroup.DisplayOrder);
//Needed to remove orange button
staticGroup.IsDifferentThanStaticGroup = false;
}
/// <summary>
/// returns a lookup of group channel id to group channel for ALL channels in a test
/// this is useful when correcting level trigger and calculated channels post a group pull/push
/// the structure returned by the function allows looking up say an input channel given an id
/// even if those channels are no longer in the test (because of push/pull operation)
/// 15400 Group Push/Pull should allow the LT to be preserved in the Test Setup regardless of push/pull
/// </summary>
/// <param name="testGroup"></param>
/// <returns></returns>
private IReadOnlyDictionary<long, IGroupChannel> GetIGroupChannelIdToIGroupChannel()
{
var lookup = new Dictionary<long, IGroupChannel>();
var channels = GetChannels();
foreach (var ch in channels)
{
if (ch.IsBlank()) { continue; }
lookup[ch.Id] = ch;
}
return lookup;
}
/// <summary>
/// this function "corrects" level trigger channels after a pull operation
/// it does this using the parameter input data which tells
/// if any channels have changed as a result of a pull operation, it then just
/// remaps those channels
/// 15400 Group Push/Pull should allow the LT to be preserved in the Test Setup regardless of push/pull
/// </summary>
/// <param name="oldChannelToNewChannel"></param>
/// <param name="testSetupChannelIdToGroupChannel"></param>
/// <param name="errors"></param>
/// <param name="viewMode"></param>
private void CorrectLevelTriggerChannels(
IReadOnlyDictionary<IGroupChannel, IGroupChannel> oldChannelToNewChannel)
{
var levelTriggerKeys = LevelTriggerChannels.Keys.ToArray();
foreach (var key in levelTriggerKeys)
{
var lt = LevelTriggerChannels[key];
if (oldChannelToNewChannel.ContainsKey(lt.GroupChannel))
{
//at this point in time we are still pre-commit for the new group
//so we just point the group channel to the new group channel
//the new group channel doesn't have valid id yet (until we commit)
lt.GroupChannel = oldChannelToNewChannel[lt.GroupChannel];
}
}
}
/// <summary>
/// this method "corrects" calculated channels after a push/pull operation
/// it does this by replacing channels from the pulled group with new channels
/// after the pull operation
/// 15400 Group Push/Pull should allow the LT to be preserved in the Test Setup regardless of push/pull
/// </summary>
/// <param name="oldChannelToNewChannel"></param>
/// <param name="testSetupChannelIdToGroupChannel"></param>
/// <param name="errors"></param>
/// <param name="viewMode"></param>
private void CorrectCalculatedChannels(
IReadOnlyDictionary<IGroupChannel, IGroupChannel> oldChannelToNewChannel,
IReadOnlyDictionary<long, IGroupChannel> testSetupChannelIdToGroupChannel,
ref List<string> errors,
IsoViewMode viewMode)
{
var currentCalculatedChannels = CalculatedChannels;
foreach (var cc in currentCalculatedChannels)
{
var inputIds = cc.InputChannelIds.ToArray();
var inputChannels = new List<IGroupChannel>();
for (var i = 0; i < inputIds.Length; i++)
{
//this is the old for the channel, it'd be more ideal if we have access
//to the group channel in the case it's a new channel not in the db, but
//I don't see how to get that info currently...
var oldId = inputIds[i];
if (long.TryParse(oldId, out var l))
{
//now get that channel from the test
//if we have a new channel, use it, otherwise use the old one
if (testSetupChannelIdToGroupChannel.ContainsKey(l))
{
var oldChannel = testSetupChannelIdToGroupChannel[l];
if (oldChannelToNewChannel.ContainsKey(oldChannel))
{
//there's a new channel that replaces the old one, so use the new one
inputChannels.Add(oldChannelToNewChannel[oldChannel]);
}
else
{
//there's no new channel replacing the old one, so just use the old one
inputChannels.Add(oldChannel);
}
}
}
}
cc.SetChannels(inputChannels.ToArray());
}
}
#region MetaData
private readonly Dictionary<char, TestObjectMetaData> _metaDataLookup = new Dictionary<char, TestObjectMetaData>();
// FB14362 This method will keep the _metaDataLookup dictionary updated to prevent the missing data from database.
public void UpdateMetaDataLookupKey(char oldKey, char newKey)
{
if (_metaDataLookup.ContainsKey(oldKey))
{
var toMetaData = new TestObjectMetaData(newKey, _metaDataLookup[oldKey]);
//Do not remove the oldKey if it presents in any other groups already.
if (!Groups.Any(p => p.TestObject.Any() && p.TestObject[0] == oldKey) && oldKey != '?')
{
_metaDataLookup.Remove(oldKey);
}
if (!_metaDataLookup.ContainsKey(newKey))
{
_metaDataLookup.Add(newKey, toMetaData);
}
}
}
public TestObjectMetaData[] GetMetaData()
{
var metas = new List<TestObjectMetaData>();
foreach (KeyValuePair<char, TestObjectMetaData> md in _metaDataLookup)
{
metas.Add(md.Value);
}
foreach (var to in TestObjects)
{
if (to.TestObject == null) continue;
var m = GetMetaData(to.TestObject.Test_Object[0]);
if (!metas.Contains(m)) { metas.Add(m); }
}
foreach (var to in AddedGroups)
{
if (to.TestObject == null) continue;
var m = GetMetaData(to.TestObject.Test_Object[0]);
if (!metas.Contains(m)) { metas.Add(m); }
}
metas.Sort(CompareMeta);
return metas.ToArray();
}
public TestObjectMetaData GetMetaData(char testobject)
{
if (!_metaDataLookup.ContainsKey(testobject))
{
_metaDataLookup.Add(testobject, new TestObjectMetaData(testobject));
}
return _metaDataLookup[testobject];
}
public TestObjectMetaData GetMetaData(char testobject, int testObjectNumber)
{
if (!_metaDataLookup.ContainsKey(testobject))
{
_metaDataLookup.Add(testobject, new TestObjectMetaData(testobject, testObjectNumber));
}
return _metaDataLookup[testobject];
}
private TestSetupMetaData _testSetupMeta = new TestSetupMetaData(DataModelSettings.RequireXCrashCompatibilityForISOExports);
public TestSetupMetaData GetTestMetaData()
{
return _testSetupMeta;
}
public void SetTestSetupMetaData(TestSetupMetaData meta)
{
_testSetupMeta = meta;
}
public void SetMetaData(char testobject, TestObjectMetaData meta)
{
_metaDataLookup[testobject] = meta;
}
public void SetMetaData(TestObjectMetaData[] metaLookup)
{
foreach (var testObjectMetaData in metaLookup)
{
_metaDataLookup[testObjectMetaData.TestObject] = testObjectMetaData;
}
}
private int CompareMeta(TestObjectMetaData left, TestObjectMetaData right)
{
if (left == right) { return 0; }
if (null == left) { return -1; }
return null == right ? 1 : left.TestObject.CompareTo(right.TestObject);
}
#endregion MetaData
public void Rename(string newName)
{
foreach (var addedGroup in AddedGroups)
{
addedGroup.Rename(Name, newName);
ReplaceSensorsInLookup(addedGroup, Name, newName);
}
RenameLevelTriggerChannels(Name, newName);
RenameCalculatedChannels(Name, newName);
GetTestMetaData().SetPropertyValue(TestSetupMetaData.Fields.Title, newName);
Name = newName;
}
}
}