11833 lines
599 KiB
Plaintext
11833 lines
599 KiB
Plaintext
|
|
//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
|
||
|
|
warnings.Add(string.Format(StringResources.EditObjectPageWarning_HardwareCalDateOverdue, h.SerialNumber, h.CalDueDate.ToShortDateString()));
|
||
|
|
}
|
||
|
|
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.SuppressViewAllViewer;
|
||
|
|
|
||
|
|
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.UploadDefault;
|
||
|
|
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)));
|
||
|
|
}
|
||
|
|
private static bool IsNotDSPFiltered(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 &&
|
||
|
|
IsNotDSPFiltered(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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|