using System; using System.Collections.Generic; using System.Linq; using DataPROWin7.Common; using DTS.Common.Classes.Hardware; using DTS.Common.Interface.DASFactory; using DTS.Common.Utilities.Logging; using DTS.DASLib.Service; using DTS.Common.SharedResource.Strings; using System.Threading; using DataPROWin7.DataModel.Classes.Hardware; using DTS.Common.Interface.Channels; using DTS.Common.Interface.Groups.GroupList; using DTS.Common.Interface.DASFactory.Config; using DTS.Common.Enums.DASFactory; using DTS.Common.Enums; using DTS.Slice.Users.UserSettings; using DTS.Common.Enums.Sensors; using DTS.Common.Classes.Groups; using DTS.SensorDB; using DTS.Common.Classes.Sensors; using DTS.Common.Constant.DASSpecific; using DTS.Common.Enums.Hardware; using DTS.Common.Classes.Groups.ChannelSettings; using DTS.Common.DataModel.Common; using DTS.Common.Enums.TSRAIRGo; using DTS.Common.DataModel.Classes.TSRAIRGo; using DTS.Common.Interface.Sensors.AnalogDiagnostics; using DTS.Common; namespace DataPROWin7.DataModel.Classes { public class LevelTriggerCapableChannel { public HardwareChannel HardwareChannel { get; } public string DASOrModuleSerialNumber { get { switch (HardwareChannel.Hardware.DASTypeEnum) { case HardwareTypes.TDAS_Pro_Rack: case HardwareTypes.TDAS_LabRack: //need module Serial Number return HardwareChannel.ModuleSerialNumber; default: return HardwareChannel.Hardware.SerialNumber; } } } private readonly SensorData _sd; private readonly IGroupChannel _groupChannel; private DTS.Common.ISO.LevelTriggerChannel _testSetupLevelTrigger = null; public LevelTriggerCapableChannel(HardwareChannel hwch, SensorData sd, SensorCalibration sc, IGroup group, IGroupChannel groupChannel) { HardwareChannel = hwch; _sd = sd; sd.Calibration = sc; _groupChannel = groupChannel; } public double LessThanValue { get; private set; } = 0D; public double GreaterThanValue { get; private set; } = 0D; private bool _isLessThanThresholdEnabled = true; public bool IsLessThanThresholdEnabled { get => _isLessThanThresholdEnabled; set { _isLessThanThresholdEnabled = value; if (null == _testSetupLevelTrigger) return; _testSetupLevelTrigger.LessThanEnabled = value; } } private bool _isGreaterThanThresholdEnabled = false; public bool IsGreatherThanThresholdEnabled { get => _isGreaterThanThresholdEnabled; set { _isGreaterThanThresholdEnabled = value; if (null == _testSetupLevelTrigger) return; _testSetupLevelTrigger.GreaterThanEnabled = value; } } public double InsideUpperBoundValue { get; private set; } = 0D; public double InsideLowerBoundValue { get; private set; } = 0D; public double OutsideUpperBoundValue { get; private set; } = 0D; public double OutsideLowerBoundValue { get; private set; } = 0D; private bool _bTriggerBetweenBounds = false; private bool _bTriggerOutsideBounds = false; public DTS.Common.ISO.LevelTriggerChannel ToISOLevelTriggerChannel() { var lt = new DTS.Common.ISO.LevelTriggerChannel( _groupChannel.Id.ToString(), HardwareChannel.GetId(), _sd.SerialNumber, !SensorConstants.IsTSRAirHighGChannel(HardwareChannel.ModuleSerialNumber) && _isGreaterThanThresholdEnabled, GreaterThanValue, !SensorConstants.IsTSRAirHighGChannel(HardwareChannel.ModuleSerialNumber) && _isLessThanThresholdEnabled, LessThanValue, InsideLowerBoundValue, InsideUpperBoundValue, OutsideLowerBoundValue, OutsideUpperBoundValue, SensorConstants.IsTSRAirHighGChannel(HardwareChannel.ModuleSerialNumber) || _bTriggerOutsideBounds, _bTriggerBetweenBounds); lt.GroupChannel = _groupChannel; return lt; } public void FromISOLevelTriggerChannel(DTS.Common.ISO.LevelTriggerChannel channel) { LessThanValue = channel.LessThanThresholdEU; GreaterThanValue = channel.GreaterThanThresholdEU; _isGreaterThanThresholdEnabled = !SensorConstants.IsTSRAirHighGChannel(HardwareChannel.ModuleSerialNumber) && channel.GreaterThanEnabled; _isLessThanThresholdEnabled = !SensorConstants.IsTSRAirHighGChannel(HardwareChannel.ModuleSerialNumber) && channel.LessThanEnabled; _testSetupLevelTrigger = channel; InsideUpperBoundValue = channel.InsideUpperLevelEU; InsideLowerBoundValue = channel.InsideLowerLevelEU; OutsideUpperBoundValue = channel.OutsideUpperLevelEU; OutsideLowerBoundValue = channel.OutsideLowerLevelEU; _bTriggerBetweenBounds = channel.TriggerBetweenBounds; _bTriggerOutsideBounds = SensorConstants.IsTSRAirHighGChannel(HardwareChannel.ModuleSerialNumber) || channel.TriggerOutsideBounds; } } public class Diagnostics { private readonly Configuration configuration = new Configuration(); public Diagnostics() { } public bool Reset(DataModel.TestTemplate currentTest, List dasList, Dictionary dasSampleRateList, DASHardware[] hardware, StatusHelpers.SetProgressValueDelegate setProgressFunction, DTS.Slice.Users.User currentUser) { DASHardware.MarkAllDASUnclean(dasList); ConnectIfNeededPartial(dasList); if (DataNeverDownloaded(dasList)) { return false; } else { return true; } } public void ContinueReset(DataModel.TestTemplate currentTest, List dasList, Dictionary dasSampleRateList, DASHardware[] hardware, StatusHelpers.SetProgressValueDelegate setProgressFunction, DTS.Slice.Users.User currentUser) { UpdateConfigAndPrepareForDiagnostics(currentTest, dasList, dasSampleRateList, hardware, setProgressFunction, currentUser); RunDiagnostics(dasList, hardware); } private void ConnectIfNeededPartial(List dasList) { var maxQueryConfigTimeout = DetermineMaxQueryConfigTime(); StartAutoResolutionPartial(dasList, maxQueryConfigTimeout); } private const int TSRAIRGO_QUERYCONFIG_TIMEOUT = 150000; private int DetermineMaxQueryConfigTime() { if (RunTestVariables.IsTSRAIRGo) { return TSRAIRGO_QUERYCONFIG_TIMEOUT; } int maxQueryConfigTimeout = 0; maxQueryConfigTimeout = Math.Max(maxQueryConfigTimeout, SerializedSettings.ResolveChannels_SLICE_QueryConfigTimeoutSec * 1000); return maxQueryConfigTimeout; } private void StartAutoResolutionPartial(List dasList, int maxQueryConfigTimeout) { BuildLookups(dasList, maxQueryConfigTimeout); } private void BuildLookups(List dasList, int maxQueryConfigTimeout) { QueryConfigurationPartial(dasList, maxQueryConfigTimeout); } private void QueryConfigurationPartial(List das, int maxQueryConfigTimeout) { try { var doneEvent = new ManualResetEvent(false); using (var cs = new ConfigurationService()) { cs.ServiceCallbackError += CS_ServiceCallbackError; cs.GetConfiguration(das, true, delegate (ServiceBase.CallbackData data) { switch (data.Status) { case ServiceBase.CallbackData.CallbackStatus.AllFinished: doneEvent.Set(); break; case ServiceBase.CallbackData.CallbackStatus.Failure: doneEvent.Set(); break; } }, das); var totalTimeWaited = 0; while (totalTimeWaited < maxQueryConfigTimeout && !doneEvent.WaitOne(100, false)) { totalTimeWaited += 100; } if (totalTimeWaited >= maxQueryConfigTimeout) { cs.Cancel(); APILogger.Log("timeout"); throw new TimeoutException(); } } } catch (Exception ex) { APILogger.Log("QueryConfig failed: " + ex.Message); throw; } } private static void CS_ServiceCallbackError(object sender, string msg, Exception caught) { APILogger.Log("error querying configuration", msg); } private void UpdateConfigAndPrepareForDiagnostics(DataModel.TestTemplate currentTest, List ldas, Dictionary dasSampleRateList, DASHardware[] hardware, StatusHelpers.SetProgressValueDelegate setProgressFunction, DTS.Slice.Users.User currentUser) { try { //Store the entire Test Setup .xml in the SETUP folder ExportCurrentTestSetup(currentTest, currentUser); //Also, store a portion (the DAS and Fields) of the Test Setup on the DAS (in the TestSetup filestore). var testSetupXML = ExportCurrentTestSetupFields(currentTest); if (testSetupXML != null) { StoreTestSetup(ldas, testSetupXML); } } catch (Exception ex) { APILogger.Log(ex); } try { var channelLookup = new Dictionary(); var channelsForDas = new Dictionary>(); foreach (var group in currentTest.Groups) { AddChannelsForDAS(channelsForDas, channelLookup, hardware); } var dasLookup = new Dictionary(); foreach (var h in hardware) { dasLookup[h.SerialNumber] = h; } foreach (var idas in ldas) { DASHardware h = null; if (dasLookup.ContainsKey(idas.SerialNumber)) { h = dasLookup[idas.SerialNumber]; } if (null == h) { h = DASHardwareList.GetList() .GetHardware(idas.SerialNumber, ((ICommunication)idas).ConnectString); } if (!channelsForDas.ContainsKey(h.DASId)) continue; foreach (var ch in channelsForDas[h.DASId]) { ch.DiagnosticStatus = DiagnosticStatus.Untested; } } UpdateConfig(currentTest, ldas, hardware, setProgressFunction, currentUser); PrepareForDiagnostics(ldas, dasSampleRateList); } catch (Exception ex) { APILogger.Log(ex); } } private static void AddChannelsForDAS(Dictionary> channelsForDas, Dictionary channelLookup, DASHardware[] hardwares) { foreach (var h in hardwares) { if (!channelsForDas.ContainsKey(h.DASId)) { channelsForDas.Add(h.DASId, new List()); } foreach (var ch in h.Channels) { if (null == ch.Sensor) continue; if (ch.IsClock) continue; var key = $"{h.DASId}_{ch.ChannelNumber}"; if (!channelLookup.ContainsKey(key)) { channelLookup[key] = ch; channelsForDas[h.DASId].Add(ch); } } } } private void ExportCurrentTestSetup(DataModel.TestTemplate currentTest, DTS.Slice.Users.User currentUser) { var path = System.IO.Path.Combine(currentTest.TestDirectory.Trim(), "SETUP"); try { if (!System.IO.Directory.Exists(path)) { System.IO.Directory.CreateDirectory(path); } var filename = System.IO.Path.Combine(path, string.IsNullOrEmpty(currentTest.TestId) ? "TestSetup.xml" : $"{currentTest.TestId}.xml"); if (System.IO.File.Exists(filename)) { System.IO.File.Delete(filename); } var includedTests = new Dictionary(); var includedGroups = new Dictionary(); var includedDAS = new Dictionary(); var includedSensors = new Dictionary(); var sensorsAlreadyAdded = new HashSet(); var includedSensorModels = new Dictionary(); var includedCalibration = new Dictionary(); var includedCustomerDetails = new Dictionary(); var includedTestEngineerDetails = new Dictionary(); var includedLabDetails = new Dictionary(); var includedUsers = new Dictionary(); var includedGlobalSettings = new Dictionary(); ExportTestSetup.PrepareForExport(currentTest, includedTests, includedGroups, includedDAS, includedSensors, sensorsAlreadyAdded, includedSensorModels, includedCalibration, includedCustomerDetails, includedTestEngineerDetails, includedLabDetails, true, false ); ExportTestSetup.ExportToFile(includedTests, includedGroups, includedDAS, includedSensors, includedSensorModels, includedCalibration, includedCustomerDetails, includedTestEngineerDetails, includedLabDetails, includedUsers, includedGlobalSettings, filename, string.Empty ); //Store as the latest Test Setup Defaults.SetUserSetting(currentUser.Id, PropertyEnums.PropertyIds.LastRunTestSetup, filename); currentTest.SetupFile = filename; } catch (Exception ex) { APILogger.Log(ex); } } private string ExportCurrentTestSetupFields(DataModel.TestTemplate currentTest) { try { var includedTests = new Dictionary(); var includedDAS = new Dictionary(); //Remove the Test Channels group var tempCurrentTest = new DataModel.TestTemplate(currentTest); tempCurrentTest.Groups.Clear(); ExportTestSetup.PrepareForExportFields(tempCurrentTest, includedTests, includedDAS); return ExportTestSetup.ExportToFileFields(includedTests, includedDAS, string.Empty ); } catch (Exception ex) { APILogger.Log(ex); return null; } } private void StoreTestSetup(List dasList, string testSetupXML) { using (var configService = new ConfigurationService()) { var mreLocal = new ManualResetEvent(false); configService.StoreTestSetupXML(dasList, delegate (ServiceBase.CallbackData cbd) { switch (cbd.Status) { case ServiceBase.CallbackData.CallbackStatus.AllFinished: mreLocal.Set(); break; } }, dasList, testSetupXML); mreLocal.WaitOne(); } } private void UpdateConfig(DataModel.TestTemplate currentTest, List ldas, DASHardware[] hardware, StatusHelpers.SetProgressValueDelegate setProgressFunction, DTS.Slice.Users.User currentUser) { SortOutConfig(currentTest, ldas, true, hardware, currentUser); var exceptionThrown = false; //Check the AAFilter rate var OkToProceed = true; try { OkToProceed = CheckAAFilterRate(ldas); } catch (Exception ex) { APILogger.Log("UpdateConfig - failed to checkaafilterrate", ex); exceptionThrown = true; } if (exceptionThrown || !OkToProceed) { return; //we have failed } foreach (var das in ldas) { setProgressFunction(das, 0D, TSRAIRGoStatus.StatusTypes.UPDATING_DAS_CONFIG); } configuration.SetConfig(currentTest, ldas, true, setProgressFunction); } public delegate void ReportErrorsDelegate(List errors); /// /// Sorts out analog channels in the test setup versus the AnalogInputDASchannel object and sets properties on the daschannel /// This function was in multiple places with near identical code, I brought it together to one place and abstracted it out of the /// huge SortOutConfig function /// /// /// /// /// /// /// /// /// /// /// /// /// /// public static bool SortOutConfigAnalog(AnalogInputDASChannel dasChannel, string key, int moduleChannelNumber, IDASCommunication das, DASHardware h, IDASModule mod, SortOutConfigParams soParams, ReportErrorsDelegate ReportErrors = null) { if (soParams.ContainsHardwareChannelDisplayOrder(key)) { dasChannel.AbsoluteDisplayOrder = soParams.GetHardwareChannelAbsoluteDisplayOrder(key); } dasChannel.ModuleChannelNumber = moduleChannelNumber; var hc = soParams.GetHardwareChannel(key); var sensor = hc.Sensor; SensorCalibration sc = null; //SensorID is the EID of the sensor, and is saved in the config so //that if the associated DAS is connected to a different computer, //this test-used EID can be found. This is helpful, for example, //when the Quick build button is used to create a new Test Setup and //the same sensor is connected to a different DAS. Prior to this //saving in the config, only the "live" EID was known when reading the config. dasChannel.SensorID = sensor.EID; foreach (var se in sensor.SupportedExcitation) { if (!dasChannel.IsSupported(se)) continue; sc = SensorCalibration.GetLatestCalibrationBySerialNumberAndExcitation(sensor, se); if (null != sc) { break; } } if (null == sc) { return false; } // 14055 use non-linear cal if we're a single-cal'd sensor or if we're a dual-cal and behavior isn't to use linear var bUseNonLinear = !sc.NonLinear || !sc.LinearAdded || CalibrationBehaviors.LinearIfAvailable != soParams.TestTemplate.CalibrationBehavior; if (sensor.Bridge == SensorConstants.BridgeType.IEPE) { dasChannel.CouplingMode = sensor.CouplingMode; } dasChannel.ACCouplingModeEnabled = sensor.ACCouplingModeEnabled; if (null != hc.GroupChannel) { var groupChannel = (GroupChannel)hc.GroupChannel; if (groupChannel.IsTSRAIRLowG) { if (groupChannel.ACCouplingEnabled) { dasChannel.ACCouplingModeEnabled = true; dasChannel.CouplingMode = SensorConstants.CouplingModes.AC; } else { dasChannel.ACCouplingModeEnabled = false; dasChannel.CouplingMode = SensorConstants.CouplingModes.DC; } } } dasChannel.BridgeResistanceOhms = sensor.BridgeResistance; if (sc.NonLinear && bUseNonLinear && sc.IRTraccCalculationType == NonLinearStyles.IRTraccCalFactor) { if (!Equals(sc.Records.Records[0].Poly.CalibrationFactor, 0.0)) { dasChannel.ZeroPoint = sc.Records.Records[0].Poly.ZeroPositionIntercept / sc.Records.Records[0].Poly.CalibrationFactor; } else { dasChannel.ZeroPoint = 0.0; } } else { dasChannel.ZeroPoint = sc.Records.Records[sc.Records.Records.Count() - 1].ZeroPoint; } dasChannel.BypassAAFilter = sensor.ByPassFilter; dasChannel.CalSignalIsEnabled = sensor.CalSignal; dasChannel.Description = sensor.Comment; dasChannel.Manufacturer = sensor.Manufacturer; dasChannel.Model = sensor.Model; dasChannel.OriginalChannelName = hc.ChannelName; dasChannel.ChannelName2 = hc.DisplayName; dasChannel.ChannelId = hc.GroupChannel.Id.ToString(); dasChannel.ChannelGroupName = hc.GroupChannel.GroupName; dasChannel.HardwareChannelName = hc.GetIdSimple(soParams.AllHardware); dasChannel.SensorCapacity = sensor.Capacity; dasChannel.SensorPolarity = sensor.Polarity; dasChannel.DesiredRangeWithHeadroomEU = sensor.Capacity * SerializedSettings.DesiredRangeOverheadPercent * MeasurementUnitList.GetMeasurementUnit(sc.Records.Records[0].EngineeringUnits).GetScalerConversionFrom(sensor.DisplayUnit); if (sensor.UniPolar) { //we only want half the above range //note SLICEWare does this slightly different and uses capacity/2D, but I think it's better to have the safety net of the headroom dasChannel.DesiredRangeWithHeadroomEU /= 2D; } dasChannel.Excitation = GetExcitationVoltageEnum(sc, hc.GroupChannel, soParams.GetChannelLookup(), sensor); //25452 non optimal gain selected for non-linear sensors if (sc.NonLinear && bUseNonLinear) { //we have to pick a gain by doing some guesswork var inputRanges = new List(das.GetNominalRanges(sensor.Bridge)); inputRanges.Sort(); //iterate through, find the smallest input range mV that satisfies the desired headroom and min value (0) var exc = DTS.Common.DAS.Concepts.Test.Module.Channel.Sensor.GetExcitationVoltageMagnitudeFromEnum(dasChannel.Excitation); int i; for (i = 0; i < inputRanges.Count - 1; i++) { double[] eu = { sc.GetPolynomialEU(0, exc), sc.GetPolynomialEU(inputRanges[i], exc) }; //this one is acceptable if both the min and max values are satisfied //we're ignoring a whole bunch of problems, like negative or inverted outputs, and so on if (eu[0] <= 1 && eu[1] >= dasChannel.DesiredRangeWithHeadroomEU) { break; } if (eu[1] <= 1 && eu[0] >= dasChannel.DesiredRangeWithHeadroomEU) { break; } } dasChannel.DesiredRangeWithHeadroomEU = inputRanges[i]; } if (sensor.IsDigitalInput() || sensor.IsDigitalOutput()) { dasChannel.DesiredRangeWithHeadroomEU = sensor.FullScaleCapacity; } dasChannel.DiagnosticsMode = sensor.DiagnosticsMode; dasChannel.EngineeringUnits = sc.Records.Records[0].EngineeringUnits; dasChannel.EventStartTime = DateTime.Now; dasChannel.InitialOffset = hc.GroupChannel.InitialOffset.ToDbSerializeString(); switch (hc.GroupChannel.InitialOffset.Form) { case InitialOffsetTypes.EU: dasChannel.InitialEU = hc.GroupChannel.InitialOffset.EU; break; default: dasChannel.InitialEU = 0D; break; } dasChannel.IsInverted = sensor.Invert; if (sensor.FilterClassIso == "?") { sensor.FilterClassIso = "P"; // "Prefiltered > CFC 1000" (Unfiltered) } dasChannel.ISOCode = hc.GroupChannel.IsoCode; //IEPE should nto be marked as proportional to excitation dasChannel.IsProportionalToExcitation = sc.IsProportional && sensor.Bridge != SensorConstants.BridgeType.IEPE; dasChannel.AtCapacity = bUseNonLinear ? sc.Records.Records[0].AtCapacity : sc.Records.Records[sc.Records.Records.Count() - 1].AtCapacity; dasChannel.SensitivityUnits = bUseNonLinear ? sc.Records.Records[0].SensitivityUnits : sc.Records.Records[sc.Records.Records.Count() - 1].SensitivityUnits; dasChannel.CapacityOutputIsBasedOn = bUseNonLinear ? sc.Records.Records[0].CapacityOutputIsBasedOn : sc.Records.Records[sc.Records.Records.Count() - 1].CapacityOutputIsBasedOn; dasChannel.UserCode = hc.UserCode; dasChannel.UserChannelName = hc.UserChannelName; dasChannel.IsoChannelName = hc.IsoChannelName; dasChannel.LastCalibrationDate = sc.CalibrationDate; dasChannel.CalDueDate = sensor.GetDueDate(sc); dasChannel.DigitalMultiplier = sensor.ScaleMultiplier; dasChannel.DIUnits = sensor.DIUnits; dasChannel.DigitalMode = sensor.InputMode; dasChannel.LinearizationFormula = new LinearizationFormula(bUseNonLinear ? sc.Records.Records[0].Poly : sc.Records.Records[sc.Records.Records.Count() - 1].Poly); dasChannel.LinearSensorCalibration = bUseNonLinear ? sc.LinearAddedValues : string.Empty; dasChannel.OffsetToleranceHighMilliVolts = sensor.OffsetToleranceHigh; dasChannel.OffsetToleranceLowMilliVolts = sensor.OffsetToleranceLow; dasChannel.RemoveOffset = sc.RemoveOffset; if (UseACCoupling(sensor, hc)) { dasChannel.RemoveOffset = false; } dasChannel.SensitivityMilliVoltsPerEU = GetSensitivity(sc, hc.GroupChannel, soParams.GetChannelLookup(), sensor, bUseNonLinear); dasChannel.UnitConverision = MeasurementUnitList.GetMeasurementUnit(sc.Records.Records[0].EngineeringUnits).GetScalerConversion(sensor.DisplayUnit); if (sc.NonLinear && bUseNonLinear && sc.IRTraccCalculationType != NonLinearStyles.Polynomial) { dasChannel.SensorCapacityEU = sensor.FullScaleCapacity; } else if (sc.NonLinear && bUseNonLinear && sc.IRTraccCalculationType == NonLinearStyles.Polynomial) { //why is this being done twice? //well at least for this type, lets not do it twice. } else if (sensor.IsDigitalInput()) { dasChannel.SensorCapacityEU = sensor.Capacity; } else if (sensor.IsDigitalOutput()) { dasChannel.SensorCapacityEU = sensor.FullScaleCapacity; } else { dasChannel.SensorCapacityEU = sensor.Capacity * MeasurementUnitList.GetMeasurementUnit(sc.Records.Records[0].EngineeringUnits).GetScalerConversionFrom(sensor.DisplayUnit); } dasChannel.SerialNumber = sensor.SerialNumber; dasChannel.Unipolar = sensor.UniPolar; dasChannel.ShuntIsEnabled = sensor.PerformShuntEmulation && !sensor.DiagnosticsMode && sensor.Bridge != SensorConstants.BridgeType.IEPE && !sensor.IsTestSpecificEmbedded; dasChannel.SoftwareFilterFrequency = sensor.FilterClass.Frequency; //FB 13120 For now we will continue using the SoftwareFilterFrequency until we move all the refrences to SoftwareFilterClass. dasChannel.SoftwareFilterClass = sensor.FilterClass; //33415 Voltage insertion channel should be half bridge dasChannel.TypeOfBridge = null != hc.GroupChannel && Array.Exists(hc.GroupChannel.ChannelSettings, chset => ChannelSettingBase.BRIDGE_TYPE == chset.SettingName) ? (SensorConstants.BridgeType)Enum.Parse(typeof(SensorConstants.BridgeType), hc.GroupChannel.ChannelSettings.First(chset => ChannelSettingBase.BRIDGE_TYPE == chset.SettingName).Value) : sensor.Bridge; dasChannel.UserValue1 = sensor.UserValue1; dasChannel.UserValue2 = sensor.UserValue2; dasChannel.UserValue3 = sensor.UserValue3; dasChannel.VerifyOffset = true; dasChannel.VoltageInsertionCheckEnabled = false; //FB14606: Test Setup Specific-ize ZeroMethod parameters dasChannel.ZeroAverageStartSeconds = hc.GroupChannel.ZeroMethodStart; dasChannel.ZeroAverageStopSeconds = hc.GroupChannel.ZeroMethodEnd; dasChannel.ZeroMethod = hc.GroupChannel.ZeroMethod; if (dasChannel.IEPEChannel != (sensor.Bridge == SensorConstants.BridgeType.IEPE)) { //IEPE status of channel disagrees with sensor, can we reprogram the DAS? if (dasChannel.CanReProgram()) { dasChannel.IEPEChannel = sensor.Bridge == SensorConstants.BridgeType.IEPE; } else { if (dasChannel.IEPEChannel) { ReportErrors?.Invoke(new List(new[] { string.Format(StringResources.EditObjectSensorsControl_InvalidIEPEOnNonIEPE, dasChannel.ChannelName2, sensor.SerialNumber) })); } else { ReportErrors?.Invoke(new List(new[] { string.Format(StringResources.EditObjectSensorsControl_InvalidNonIEPEOnIEPE, dasChannel.ChannelName2, sensor.SerialNumber) })); } //FAIL ? } } dasChannel.TriggerBelowThresholdEu = null; dasChannel.TriggerAboveThresholdEu = null; dasChannel.LevelTriggerType = DTS.Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.NONE; //the edittestsetupleveltrigger is a convenient wrapper and easier that the isoleveltrigger, so I use it here. var lt = new LevelTriggerCapableChannel(hc, sensor, sc, soParams.GetGroupFromChannelId(hc.GroupChannel.Id), hc.GroupChannel); //ReSharper disable once InconsistentNaming var existingLT = soParams.TestTemplate.GetLevelTrigger(lt.ToISOLevelTriggerChannel()); if (null != existingLT) { lt.FromISOLevelTriggerChannel(existingLT); if (h.IsTSRAIR()) { if (existingLT.TriggerOutsideBounds) { dasChannel.LevelTriggerType = DTS.Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.OutsideWindow; dasChannel.TriggerAboveThresholdEu = lt.OutsideUpperBoundValue; dasChannel.TriggerBelowThresholdEu = lt.OutsideLowerBoundValue; } } else { if (existingLT.TriggerBetweenBounds) { dasChannel.LevelTriggerType = DTS.Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.InsideWindow; dasChannel.TriggerAboveThresholdEu = lt.InsideUpperBoundValue; dasChannel.TriggerBelowThresholdEu = lt.InsideLowerBoundValue; } else if (existingLT.TriggerOutsideBounds) { dasChannel.LevelTriggerType = DTS.Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.OutsideWindow; dasChannel.TriggerBelowThresholdEu = lt.OutsideLowerBoundValue; dasChannel.TriggerAboveThresholdEu = lt.OutsideUpperBoundValue; } else if (existingLT.GreaterThanEnabled && existingLT.LessThanEnabled) { dasChannel.LevelTriggerType = DTS.Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.GreaterThan | DTS.Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.LessThan; dasChannel.TriggerAboveThresholdEu = lt.GreaterThanValue; dasChannel.TriggerBelowThresholdEu = lt.LessThanValue; } else if (existingLT.LessThanEnabled) { dasChannel.LevelTriggerType = DTS.Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.LessThan; dasChannel.TriggerBelowThresholdEu = lt.LessThanValue; } else if (existingLT.GreaterThanEnabled) { dasChannel.LevelTriggerType = DTS.Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.GreaterThan; dasChannel.TriggerAboveThresholdEu = lt.GreaterThanValue; } } } if (h.IsTSRAIR()) { //18057 set channel's supersampling rate dasChannel.UnsupersampledSampleRate = soParams.TestTemplate.GetSampleRateForEmbeddedHardware(h, das.DASInfo.Modules[mod.ModuleArrayIndex].TypeOfModule); } return true; } /// /// sorts out the squib properties from the test setup and sets properties on the squibchannel /// /// /// /// /// /// /// /// /// /// public static void SortOutConfigSquib(ref int currentChannelIdx, IDASModule mod, string key, ref int moduleChannelNumber, IDASChannel c, IDASCommunication das, SortOutConfigParams soParams) { currentChannelIdx++; //It's OK to increment this here because we need to handle both squib channels (Voltage and Current) OutputSquibChannel squib2 = null; if (currentChannelIdx < mod.Channels.Length) { squib2 = mod.Channels[currentChannelIdx] as OutputSquibChannel; } if (null == squib2) { throw new NotSupportedException("require both VO and CU channels"); } var outputSquibChannel = c as OutputSquibChannel; if ( soParams.ContainsHardwareChannelDisplayOrder(key)) { outputSquibChannel.AbsoluteDisplayOrder = soParams.GetHardwareChannelAbsoluteDisplayOrder(key); squib2.AbsoluteDisplayOrder = outputSquibChannel.AbsoluteDisplayOrder; } outputSquibChannel.ModuleChannelNumber = moduleChannelNumber; moduleChannelNumber++; squib2.ModuleChannelNumber = moduleChannelNumber; var hc = soParams.GetHardwareChannel(key); var sensor = hc.Sensor; //SensorID is the EID of the sensor, and is saved in the config so //that if the associated DAS is connected to a different computer, //this test-used EID can be found. This is helpful, for example, //when the Quick build button is used to create a new Test Setup and //the same sensor is connected to a different DAS. Prior to this //saving in the config, only the "live" EID was known when reading the config. outputSquibChannel.IDs = new EID[] { new EID(sensor.EID) }; sensor.ISOCode = hc.GroupChannel.IsoCode; foreach (var se in sensor.SupportedExcitation) { var sc = SensorCalibration .GetLatestCalibrationBySerialNumberAndExcitation(sensor, se); if (null != sc) { break; } } outputSquibChannel.DiagnosticsMode = false; squib2.DiagnosticsMode = false; outputSquibChannel.EventStartTime = DateTime.Now; squib2.EventStartTime = DateTime.Now; var isocode = new DTS.Common.ISO.IsoCode(sensor.ISOCode) { PhysicalDimension = "VO" }; outputSquibChannel.ISOCode = isocode.StringRepresentation; isocode.PhysicalDimension = "CU"; squib2.ISOCode = isocode.StringRepresentation; outputSquibChannel.UserCode = hc.GroupChannel.UserCode; outputSquibChannel.UserChannelName = hc.GroupChannel.UserChannelName; outputSquibChannel.IsoChannelName = hc.GroupChannel.IsoChannelName; squib2.UserCode = outputSquibChannel.UserCode; squib2.UserChannelName = outputSquibChannel.UserChannelName; squib2.IsoChannelName = outputSquibChannel.IsoChannelName; outputSquibChannel.BypassCurrentFilter = sensor.BypassCurrentFilter; squib2.BypassCurrentFilter = outputSquibChannel.BypassCurrentFilter; outputSquibChannel.BypassVoltageFilter = sensor.BypassVoltageFilter; squib2.BypassVoltageFilter = outputSquibChannel.BypassVoltageFilter; outputSquibChannel.ConfigurationMode = DFConstantsAndEnums.ConfigMode.Normal; squib2.ConfigurationMode = DFConstantsAndEnums.ConfigMode.Normal; outputSquibChannel.Date = DateTime.Now; squib2.Date = DateTime.Now; outputSquibChannel.DelayMS = sensor.SquibFireDelayMS; squib2.DelayMS = sensor.SquibFireDelayMS; outputSquibChannel.DiagnosticsMode = false; squib2.DiagnosticsMode = false; outputSquibChannel.DurationMS = sensor.SquibFireDurationMS; squib2.DurationMS = outputSquibChannel.DurationMS; outputSquibChannel.LimitDuration = sensor.LimitSquibFireDuration; squib2.LimitDuration = outputSquibChannel.LimitDuration; outputSquibChannel.MeasurementType = sensor.SquibMeasurementType; squib2.MeasurementType = SquibMeasurementType.CURRENT; outputSquibChannel.FireMode = sensor.SquibFireMode; squib2.FireMode = outputSquibChannel.FireMode; outputSquibChannel.SquibDescription = sensor.Comment; squib2.SquibDescription = sensor.Comment; outputSquibChannel.SquibFiredPassed = false; squib2.SquibFiredPassed = false; outputSquibChannel.SquibFiredValid = false; squib2.SquibFiredPassed = outputSquibChannel.SquibFiredPassed; outputSquibChannel.SquibToleranceHigh = sensor.SquibToleranceHigh; squib2.SquibToleranceHigh = outputSquibChannel.SquibToleranceHigh; outputSquibChannel.SquibToleranceLow = sensor.SquibToleranceLow; squib2.SquibToleranceLow = outputSquibChannel.SquibToleranceLow; outputSquibChannel.SquibOutputCurrent = sensor.SquibOutputCurrent; squib2.SquibOutputCurrent = outputSquibChannel.SquibOutputCurrent; outputSquibChannel.UserValue1 = sensor.UserValue1; squib2.UserValue1 = outputSquibChannel.UserValue1; outputSquibChannel.UserValue2 = sensor.UserValue2; squib2.UserValue2 = outputSquibChannel.UserValue2; outputSquibChannel.UserValue3 = sensor.UserValue3; squib2.UserValue3 = outputSquibChannel.UserValue3; outputSquibChannel.ChannelName2 = hc.DisplayName; outputSquibChannel.ChannelId = hc.GroupChannel.Id.ToString(); outputSquibChannel.Sensor = hc.GroupChannel.SensorData.SerialNumber.ToString(); squib2.SerialNumber = hc.GroupChannel.SensorData.SerialNumber; outputSquibChannel.SerialNumber = hc.GroupChannel.SensorData.SerialNumber; outputSquibChannel.ChannelGroupName = hc.GroupChannel.GroupName; squib2.ChannelId = hc.GroupChannel.Id.ToString() + Constants.CURRENT_SUFFIX; squib2.Sensor = hc.GroupChannel.SensorData.SerialNumber.ToString() + Constants.CURRENT_SUFFIX; squib2.ChannelGroupName = hc.GroupChannel.GroupName; squib2.ChannelName2 = hc.DisplayName; if (squib2.SquibDescription.EndsWith(".1")) { var newName = squib2.SquibDescription; newName = newName.Substring(0, newName.Length - 2) + ".2"; squib2.ChannelName2 = squib2.ChannelName2.Replace(squib2.SquibDescription, newName); } outputSquibChannel.HardwareChannelName = hc.GetIdSimple(); squib2.HardwareChannelName = hc.GetIdSimple(); //8747 - controls the default software filter for this channel //by using a harcoded filter, like TDC does if (SerializedSettings.UseLegacyTOMCFC && soParams.TestTemplate.DASSampleRateList[das.SerialNumber] > TestObjectHelper.TDC_LEGACY_TOM_CUTOFF_SPS) { outputSquibChannel.SoftwareFilterFrequency = TestObjectHelper.TDC_LEGACY_TOM_HIGH_FILTER; squib2.SoftwareFilterFrequency = TestObjectHelper.TDC_LEGACY_TOM_HIGH_FILTER; } } /// /// sorts out TOMdigital properties from the test setup and sets the properties on the DASChannel /// /// /// /// /// /// public static void SortOutConfigTOMDigitalChannel(IDASChannel c, string key, int moduleChannelNumber, SortOutConfigParams soParams) { var dOut = c as OutputTOMDigitalChannel; if (soParams.ContainsHardwareChannelDisplayOrder(key)) { dOut.AbsoluteDisplayOrder = soParams.GetHardwareChannelAbsoluteDisplayOrder(key); } dOut.ModuleChannelNumber = moduleChannelNumber; var hc = soParams.GetHardwareChannel(key); var sensor = hc.Sensor; //SensorID is the EID of the sensor, and is saved in the config so //that if the associated DAS is connected to a different computer, //this test-used EID can be found. This is helpful, for example, //when the Quick build button is used to create a new Test Setup and //the same sensor is connected to a different DAS. Prior to this //saving in the config, only the "live" EID was known when reading the config. dOut.IDs = new EID[] { new EID(sensor.EID) }; dOut.DiagnosticsMode = false; dOut.EventStartTime = DateTime.Now; if (sensor.FilterClassIso == "?") { sensor.FilterClassIso = "P"; // "Prefiltered > CFC 1000" (Unfiltered) } dOut.ConfigurationMode = DFConstantsAndEnums.ConfigMode.Normal; dOut.DelayMS = sensor.DigitalOutputDelayMS; dOut.DiagnosticsMode = false; dOut.DigitalChannelDescription = sensor.SerialNumber; dOut.LimitDuration = sensor.DigitalOutputLimitDuration; dOut.DurationMS = dOut.LimitDuration ? sensor.DigitalOutputDurationMS : 0; dOut.OutputMode = sensor.DigitalOutputMode; dOut.HardwareChannelName = hc.GetIdSimple(); dOut.IsoChannelName = sensor.ISOChannelName; } /// /// this is the overall sortoutconfig function that was in multiple places, I tried to encapsulate and clean it up a little /// /// /// /// /// /// public static void SortOutConfig(DataModel.TestTemplate currentTest, List ldas, bool clearDiagnostics, DASHardware[] allHardware, DTS.Slice.Users.User currentUser) { //18413 Diagnostics has not been run error message when using trigger check before realtime. if (clearDiagnostics) { DASHardware.MarkAllDASUnclean(ldas); } // set the test setup das order index for any das that support it // used in 14531 Implement TMATS support for S6A stream on boot var currentDasIndex = 0; foreach (var das in ldas) { if (das is DTS.Common.Interface.TestSetups.ITestDASOrder iTestDASOrder) { iTestDASOrder.DASIndex = currentDasIndex++; } } var soParams = new SortOutConfigParams() { TestTemplate = currentTest }; foreach (var group in currentTest.Groups) { soParams.AddGroupChannels(currentTest.ChannelsForGroup[group]); } foreach (var group in currentTest.Groups) { AddAndOrderChannels(group, soParams); } currentTest.FilterLookup = soParams.FilterLookup; soParams.SetAllHardware(currentTest.GetHardware()); foreach (var das in ldas) { if (null == das.ConfigData) { continue; } SortOutConfigDAS(das, currentUser, soParams); } } /// /// this was the portion of sort out config that applied to DAS, I abstracted it out to it's own function /// for readability /// /// /// /// /// /// /// /// /// /// public static void SortOutConfigDAS(IDASCommunication das, DTS.Slice.Users.User currentUser, SortOutConfigParams soParams, ReportErrorsDelegate reportErrors = null) { if (!soParams.ContainsHardware(das.SerialNumber)) { //this das is not part of the test (but may have configured channels, we need to set them to not collect data) foreach (var module in das.ConfigData.Modules) { foreach (var c in module.Channels) { DisableChannel(c); } } return; } var h = soParams.GetHardware(das.SerialNumber); if (null == h) { return; } var moduleNumber = 0; var absoluteDisplayMax = 0; if (soParams.GetHardwareChannelToAbsoluteDisplayOrderCount() > 0) { absoluteDisplayMax = soParams.GetMaxAbsoluteDisplayOrder(); } foreach (var mod in das.ConfigData.Modules) { //this is just to make sure the profile is intialized, the StreamOutputModule will get set during processing below mod.StreamProfile = (UDPStreamProfile)Enum.Parse(typeof(UDPStreamProfile), Defaults.GetUserSettingValueString(currentUser.Id, PropertyEnums.PropertyIds.DefaultUDPStreamProfile)); var moduleChannelNumber = 0; for (var currentChannelIdx = 0; currentChannelIdx < mod.Channels.Length; currentChannelIdx++) { var c = mod.Channels[currentChannelIdx]; var key = $"{h.DASId}_{c.Number}"; var hc = soParams.GetHardwareChannel(key); if (mod.IsClock()) { c.ConfigurationMode = DFConstantsAndEnums.ConfigMode.Clock; if (c is TimestampDASChannel tsdasChannel) { tsdasChannel.AbsoluteDisplayOrder = ++absoluteDisplayMax; tsdasChannel.ModuleChannelNumber = moduleChannelNumber; } } else if (null == hc || null == hc.Sensor) { DisableChannel(c); } else if (mod.IsUart()) { c.ConfigurationMode = DFConstantsAndEnums.ConfigMode.UART; if (c is UARTInputDASChannel uartChannel) { uartChannel.AbsoluteDisplayOrder = ++absoluteDisplayMax; uartChannel.ModuleChannelNumber = moduleChannelNumber; uartChannel.SerialNumber = hc.Sensor.SerialNumber; uartChannel.HardwareChannelName = hc.GetIdSimple(soParams.AllHardware); } } else if (mod.IsStreamOut()) { c.ConfigurationMode = DFConstantsAndEnums.ConfigMode.StreamOut; if (c is StreamOutputDASChannel streamOut) { streamOut.AbsoluteDisplayOrder = ++absoluteDisplayMax; streamOut.ModuleChannelNumber = moduleChannelNumber; streamOut.SerialNumber = hc.Sensor.SerialNumber; streamOut.HardwareChannelName = hc.GetIdSimple(soParams.AllHardware); mod.StreamProfile = hc.Sensor.StreamOutUDPProfile; } } else if (mod.IsStreamIn()) { c.ConfigurationMode = DFConstantsAndEnums.ConfigMode.StreamIn; if (c is StreamInputDASChannel streamIn) { streamIn.AbsoluteDisplayOrder = ++absoluteDisplayMax; streamIn.ModuleChannelNumber = moduleChannelNumber; streamIn.SerialNumber = hc.Sensor.SerialNumber; streamIn.HardwareChannelName = hc.GetIdSimple(soParams.AllHardware); } } else { c.ConfigurationMode = DFConstantsAndEnums.ConfigMode.Normal; if (c is AnalogInputDASChannel dasChannel) { if (!SortOutConfigAnalog(dasChannel, key, moduleChannelNumber, das, h, mod, soParams, reportErrors)) { continue; } } else if (c is OutputSquibChannel) { SortOutConfigSquib(ref currentChannelIdx, mod, key, ref moduleChannelNumber, c, das, soParams); } else if (c is OutputTOMDigitalChannel) { SortOutConfigTOMDigitalChannel(c, key, moduleChannelNumber, soParams); } } moduleChannelNumber++; } var filterrate = Convert.ToUInt32(soParams.TestTemplate.GetAAFForHardware(h)); mod.AAFilterRateHz = filterrate; mod.PostTriggerSeconds = soParams.TestTemplate.GetPostTriggerSeconds(das.SerialNumber); mod.PreTriggerSeconds = soParams.TestTemplate.GetPreTriggerSeconds(das.SerialNumber); mod.NumberOfEvents = soParams.TestTemplate.NumberOfEvents; mod.WakeUpMotionTimeout = soParams.TestTemplate.WakeUpMotionTimeout; mod.RecordingMode = RecordingModeExtensions.FromRecordingModes(soParams.TestTemplate.RecordingMode); switch (soParams.TestTemplate.RecordingMode) { case RecordingModes.Interval: mod.ScheduledStartTime = soParams.TestTemplate.RTCScheduleStartDateTime; mod.RecordingInterval = soParams.TestTemplate.IntervalBetweenEventStartsMinutes; break; case RecordingModes.Scheduled: mod.ScheduledStartTime = soParams.TestTemplate.RTCScheduleStartDateTime; break; case RecordingModes.MultipleEventCircularBufferPlusUART: mod.RecordingMode = DFConstantsAndEnums.RecordingMode.AutoCircularBufferPlusUART; break; case RecordingModes.MultipleEventRecorderPlusUART: mod.RecordingMode = DFConstantsAndEnums.RecordingMode.AutoRecorderModePlusUART; break; case RecordingModes.ContinuousRecorderPlusUART: mod.RecordingMode = DFConstantsAndEnums.RecordingMode.ContinuousRecorderModePlusUART; break; case RecordingModes.Active: case RecordingModes.MultipleEventActive: mod.RecordingMode = SetActiveRecordingMode(soParams.TestTemplate); break; } mod.SampleRateHz = Convert.ToUInt32(soParams.TestTemplate.GetSampleRateForHardware(h)); mod.FirmwareVersion = das.DASInfo.Modules[moduleNumber].FirmwareVersion; mod.MaxEventStorageSpaceInBytes = das.DASInfo.Modules[moduleNumber].MaxEventStorageSpaceInBytes; moduleNumber++; } das.ConfigData.TestID = soParams.TestTemplate.Name; das.ConfigData.TestSetupUniqueId = soParams.TestTemplate.TestSetupUniqueId; das.ConfigData.Description = soParams.TestTemplate.Description; das.ConfigData.InstanceID = soParams.TestTemplate.TestId; if ( das is IAlignUDPToPPSAware alignAware) { alignAware.AlignUDPToPPS = soParams.TestTemplate.AlignUDPToPPS; } } public class SortOutConfigParams { private Dictionary _channelLookup = new Dictionary(); private readonly Dictionary _harwarechanneltoAbsoluteDisplayOrder = new Dictionary(); public int GetHardwareChannelToAbsoluteDisplayOrderCount() { return _harwarechanneltoAbsoluteDisplayOrder.Count; } public bool ContainsHardwareChannelDisplayOrder(string key) { return _harwarechanneltoAbsoluteDisplayOrder.ContainsKey(key); } public int GetHardwareChannelAbsoluteDisplayOrder(string key) { return _harwarechanneltoAbsoluteDisplayOrder.ContainsKey(key) ? _harwarechanneltoAbsoluteDisplayOrder[key] : -1; } public int GetMaxAbsoluteDisplayOrder() { return _harwarechanneltoAbsoluteDisplayOrder.Values.Max(); } public Dictionary FilterLookup { get; private set; } = new Dictionary(); private readonly List _channels = new List(); public void AddGroupChannels(IGroupChannel [] channels) { _channels.AddRange(channels); _channels.Sort((a, b) => a.TestSetupOrder.CompareTo(b.TestSetupOrder)); } public void SetAbsoluteDisplayOrderFromIndex(string key, IGroupChannel ch) { _harwarechanneltoAbsoluteDisplayOrder[key] = _channels.IndexOf(ch); } public HardwareChannel GetHardwareChannel(string key) { return _channelLookup.ContainsKey(key) ? _channelLookup[key] : null; } public void SetHardwareChannel(string key, HardwareChannel channel) { _channelLookup[key] = channel; } public void SetChannelLookup(Dictionary lookup) { _channelLookup = lookup; } public Dictionary GetChannelLookup() { return _channelLookup; } private readonly Dictionary _channelIdToGroup = new Dictionary(); public IGroup GetGroupFromChannelId(long id) { return _channelIdToGroup.ContainsKey(id) ? _channelIdToGroup[id] : null; } public void SetChannelIdToGroup(long id, IGroup group) { _channelIdToGroup[id] = group; } public DataModel.TestTemplate TestTemplate { get; set; } = new DataModel.TestTemplate(); public DASHardware [] AllHardware { get; private set; } public void SetAllHardware(DASHardware[] hardware) { AllHardware = hardware; _hardwareToSerialLookup.Clear(); SetHardwareLookupEntries(hardware); } public void SetHardwareLookupEntries(DASHardware [] hardware) { foreach (var h in hardware) { _hardwareToSerialLookup[h.SerialNumber] = h; } } private readonly Dictionary _hardwareToSerialLookup = new Dictionary(); public bool ContainsHardware(string serialNumber) { return _hardwareToSerialLookup.ContainsKey(serialNumber); } public DASHardware GetHardware(string serialNumber) { return _hardwareToSerialLookup.ContainsKey(serialNumber) ? _hardwareToSerialLookup[serialNumber] : null; } } public static void AddAndOrderChannels(IGroup group, SortOutConfigParams soParams) { var hardware = soParams.TestTemplate.GetHardware(); foreach (var h in hardware) { foreach (var ch in h.Channels) { if (null == ch.Sensor) continue; var key = $"{h.DASId}_{ch.ChannelNumber}"; soParams.SetHardwareChannel(key, ch); try { if (soParams.FilterLookup.ContainsKey(key)) { //item with same key is already added, previously spammed the log with this... } else { soParams.FilterLookup.Add(key, ch.Sensor.Filter.Frequency); } } catch (Exception ex) { APILogger.Log("************************** " + ch.GetId() + " " + ex.Message + " **************"); } } } var groupChannels = soParams.TestTemplate.ChannelsForGroup[group].ToList(); groupChannels.Sort((a, b) => a.TestSetupOrder.CompareTo(b.TestSetupOrder)); foreach (var ch in groupChannels) { if (ch.SensorId < 0 || ch.DASId < 0 || ch.DASChannelIndex < 0) { continue; } var key = $"{ch.DASId}_{ch.DASChannelIndex}"; soParams.SetChannelIdToGroup(ch.Id, group); soParams.SetAbsoluteDisplayOrderFromIndex(key, ch); } } private static void DisableChannel(IDASChannel c) { c.ConfigurationMode = DFConstantsAndEnums.ConfigMode.Disabled; if (c is AnalogInputDASChannel dasChannel) { dasChannel.ChannelName2 = ""; dasChannel.SerialNumber = ""; dasChannel.SensorCapacityEU = 1; dasChannel.SensorCapacity = 0; dasChannel.SensorPolarity = ""; dasChannel.TriggerAboveThresholdEu = null; dasChannel.TriggerBelowThresholdEu = null; dasChannel.LevelTriggerType = DTS.Common.DAS.Concepts.DAS.Channel.LevelTriggerTypes.NONE; } else if (c is OutputSquibChannel outputSquibChannel) { outputSquibChannel.FireMode = SquibFireMode.NONE; } else if (c is OutputTOMDigitalChannel dOut) { dOut.ConfigurationMode = DFConstantsAndEnums.ConfigMode.Disabled; dOut.OutputMode = DigitalOutputModes.NONE; } } public static ExcitationVoltageOptions.ExcitationVoltageOption GetExcitationVoltageEnum(SensorCalibration sc, IGroupChannel c, Dictionary channelLookup, SensorData sd) { var preferredExcitation = sd.SupportedExcitation[0]; if (c.DASId < 0 || c.DASChannelIndex < 0) { return preferredExcitation; } var key = $"{c.DASId}_{c.DASChannelIndex}"; //find the appropriate excitation var h = channelLookup[key]; foreach (var se in sd.SupportedExcitation) { if (!h.IsSupportedExcitation(se)) continue; preferredExcitation = se; break; } return preferredExcitation; } private static bool UseACCoupling(SensorData sensor, HardwareChannel channel) { if (null == sensor || null == channel) { return false; } switch (sensor.Bridge) { case SensorConstants.BridgeType.DigitalInput: case SensorConstants.BridgeType.IEPE: case SensorConstants.BridgeType.RTC: case SensorConstants.BridgeType.SQUIB: case SensorConstants.BridgeType.StreamOut: case SensorConstants.BridgeType.StreamIn: case SensorConstants.BridgeType.TOMDigital: case SensorConstants.BridgeType.UART: return false; } if (!sensor.ACCouplingModeEnabled) { return false; } if (channel.Hardware.ProtocolVersion < SLICE6AIR.AC_COUPLER_ENABLE) { return false; } if (channel.Hardware.DASTypeEnum != HardwareTypes.SLICE6_AIR) { return false; } return true; } public static double GetSensitivity(SensorCalibration sc, IGroupChannel c, Dictionary channelLookup, SensorData sd, bool useNonLinear) { var preferredExcitation = sd.SupportedExcitation[0]; if ((sd.SupportedExcitation.Length > 1) && (c.DASId >= 0 && c.DASChannelIndex >= 0)) { //find the appropriate excitation var key = $"{c.DASId}_{c.DASChannelIndex}"; if (channelLookup.ContainsKey(key)) { var h = channelLookup[key]; foreach (var se in sd.SupportedExcitation) { if (!h.IsSupportedExcitation(se)) continue; preferredExcitation = se; break; } } else { //hardware not found, just return the first excitation? APILogger.Log( $"warning, failed to find hardware {c.IsoChannelName}/{c.UserChannelName} - {c.DASId}:{c.DASChannelIndex}"); } } //nonlinear cal records are first, linear last var record = useNonLinear ? Array.Find(sc.Records.Records, r => r.Excitation == preferredExcitation || !sc.IsProportional) : sc.Records.Records.LastOrDefault(r => r.Excitation == preferredExcitation || !sc.IsProportional); if (null == record) { throw new NotSupportedException("no calibration record found for " + sc.SerialNumber + " for excitation " + preferredExcitation); } //now finally, do any math we need return record.Sensitivity; } public static DFConstantsAndEnums.RecordingMode SetActiveRecordingMode(DataModel.TestTemplate currentTest) { var result = DFConstantsAndEnums.RecordingMode.AutoActiveMode; if (currentTest.WakeUpWithMotion) { result = DFConstantsAndEnums.RecordingMode.AerospaceWithMotion; } else if (currentTest.StartWithEvent) { result = DFConstantsAndEnums.RecordingMode.MultipleEventRecorderTriggerStart; } return result; } public bool CheckAAFilterRate(List dasList) { var result = true; var failureList = new List(); using (var configService = new ConfigurationService()) { var mreLocal = new ManualResetEvent(false); configService.CheckAAFilterRate(dasList, delegate (ServiceBase.CallbackData cbd) { switch (cbd.Status) { case ServiceBase.CallbackData.CallbackStatus.Failure: failureList.Add(cbd.Target.SerialNumber); break; case ServiceBase.CallbackData.CallbackStatus.AllFinished: mreLocal.Set(); break; } }, dasList); mreLocal.WaitOne(); } if (failureList.Any()) { result = false; } return result; } private void PrepareForDiagnostics(List ldas, Dictionary dasSampleRateList) { using (var diagnosticsService = new DiagnosticsService()) { var sampleRateLookup = new Dictionary(); var aafLookup = new Dictionary(); foreach (var serialNumber in ldas.Where(x => dasSampleRateList.ContainsKey(x.SerialNumber)).Select(y=>y.SerialNumber)) { var sampleRate = dasSampleRateList[serialNumber]; sampleRateLookup.Add(serialNumber, sampleRate); aafLookup.Add(serialNumber, Convert.ToSingle(SerializedSettings.GetAAFException(SerializableAAF.DAS_TYPE.SLICE, sampleRate))); } var mre = new ManualResetEvent(false); diagnosticsService.PrepareForDiagnostics(ldas, PrePostResults.PreEventDiagnosticsResult, sampleRateLookup, aafLookup, delegate (ServiceBase.CallbackData callbackData) { switch (callbackData.Status) { case ServiceBase.CallbackData.CallbackStatus.Success: break; case ServiceBase.CallbackData.CallbackStatus.Progress: break; case ServiceBase.CallbackData.CallbackStatus.NewData: break; case ServiceBase.CallbackData.CallbackStatus.Failure: callbackData.Target.DiagnosticsHasBeenRun = false; break; case ServiceBase.CallbackData.CallbackStatus.Canceled: callbackData.Target.DiagnosticsHasBeenRun = false; break; case ServiceBase.CallbackData.CallbackStatus.AllFinished: mre.Set(); break; } }, ldas); var timeWaited = 0; int MaxTime = 0; MaxTime = Math.Max(MaxTime, SerializedSettings.Diagnostics_Slice_TimeoutSec * 1000); while (!mre.WaitOne(100, false) && timeWaited < MaxTime) { timeWaited += 100; } if (timeWaited >= MaxTime) { APILogger.Log( "Diagnostics::Exiting early due to timeout"); } } } private bool DataNeverDownloaded(List dasList) { int maxQueryDownloadTimeout = 0; maxQueryDownloadTimeout = Math.Max(maxQueryDownloadTimeout, SerializedSettings.ResolveChannels_SLICE_QueryDownloadTimeoutSec * 1000); CheckForData(dasList, maxQueryDownloadTimeout); var bHaveUnDownloadedData = false; foreach (var downloadStatus in dasList.Select(x=>x.EventDownloadedStatus)) { if (bHaveUnDownloadedData) { break; } if ((null != downloadStatus) && Array.Exists(downloadStatus, b => !b)) { bHaveUnDownloadedData = true; } } return bHaveUnDownloadedData; } protected void CheckForData(List dasList, int maxQueryDownloadTimeout) { using (var ds = new DownloadService()) { var mre = new ManualResetEvent(false); var cancelEvent = new ManualResetEvent(false); var doneEvent = new ManualResetEvent(false); ds.QueryDownloadedStatus(dasList, delegate (ServiceBase.CallbackData callbackData) { switch (callbackData.Status) { case ServiceBase.CallbackData.CallbackStatus.Canceled: case ServiceBase.CallbackData.CallbackStatus.Failure: cancelEvent.Set(); mre.Set(); break; case ServiceBase.CallbackData.CallbackStatus.AllFinished: mre.Set(); break; } }, dasList); var timeWaited = 0; while (!cancelEvent.WaitOne(0, false) && !doneEvent.WaitOne(0, false) && !mre.WaitOne(100, false) && timeWaited < maxQueryDownloadTimeout) { timeWaited += 100; var percent = 100D * timeWaited / maxQueryDownloadTimeout; APILogger.Log($"{StringResources.CheckHardwareStatus_CheckingDAS} {percent:F0}%"); } if (timeWaited >= maxQueryDownloadTimeout || cancelEvent.WaitOne(0, false) || doneEvent.WaitOne(0, false)) { cancelEvent.Set(); } } } private void RunDiagnostics(List ldas, DASHardware[] hardware) { using (var diagnosticsService = new DiagnosticsService()) { var mre = new ManualResetEvent(false); var cancelEvent = new ManualResetEvent(false); var doneEvent = new ManualResetEvent(false); var workEventDone = new ManualResetEvent(false); var preOrPost = PrePostResults.PreEventDiagnosticsResult; if (ldas.Count > 0) { try { diagnosticsService.SetStatusIndicator(ldas, DiagnosticsStatusIndicatorState.Pending, delegate (ServiceBase.CallbackData callbackData) { switch (callbackData.Status) { case ServiceBase.CallbackData.CallbackStatus.AllFinished: mre.Set(); break; } }, ldas); } catch (Exception ex) { APILogger.Log(ex); diagnosticsService.Cancel(); Thread.Sleep(100); cancelEvent.Set(); return; } var totalTime = 0; int MaxTime = 0; MaxTime = Math.Max(MaxTime, SerializedSettings.Diagnostics_Slice_TimeoutSec * 1000); while (totalTime < MaxTime && !cancelEvent.WaitOne(0, false) && !doneEvent.WaitOne(0, false) && !mre.WaitOne(10, false)) { totalTime += 10; } if (totalTime >= MaxTime || cancelEvent.WaitOne(0, false) || doneEvent.WaitOne(0, false)) { APILogger.Log("Diagnostics::Exiting early due to timeout or user cancel"); diagnosticsService.ForceCancel(); Thread.Sleep(100); cancelEvent.Set(); return; } //keep track of what units failed and why so we can warn later //17822 DataPRO and TDAS rack unresponsive during diagnostics var failedUnits = new List>(); try { diagnosticsService.Diagnos(ldas, 0, preOrPost, delegate (ServiceBase.CallbackData callbackData) { switch (callbackData.Status) { case ServiceBase.CallbackData.CallbackStatus.Success: callbackData.Target.DiagnosticsHasBeenRun = true; foreach (var h in hardware) { if (h.SerialNumber != callbackData.Target.SerialNumber) continue; if (null == ((InfoResult)callbackData.Target.DASInfo).OwningDAS.BaseInput) continue; h.MeasuredInputVoltage = Math.Round(((InfoResult)callbackData.Target.DASInfo).OwningDAS.BaseInput.InputMilliVolts / 1000D, 2); h.MeasuredBatteryVoltage = Math.Round(((InfoResult)callbackData.Target.DASInfo).OwningDAS.BaseInput.BatteryMilliVolts / 1000D, 2); } break; case ServiceBase.CallbackData.CallbackStatus.Progress: case ServiceBase.CallbackData.CallbackStatus.NewData: break; case ServiceBase.CallbackData.CallbackStatus.Failure: callbackData.Target.DiagnosticsHasBeenRun = false; var msg = callbackData.ErrorMessage; if (callbackData.ErrorException is TriggerShortedException) { msg = string.Format(StringResources.Diagnostics_ShortedTrigger); } failedUnits.Add(new Tuple(callbackData.Target, msg)); break; case ServiceBase.CallbackData.CallbackStatus.Canceled: callbackData.Target.DiagnosticsHasBeenRun = false; break; case ServiceBase.CallbackData.CallbackStatus.AllFinished: mre.Set(); break; } }, ldas, MaxTime); } catch (Exception ex) { APILogger.Log(ex.Message); diagnosticsService.ForceCancel(); Thread.Sleep(100); cancelEvent.Set(); return; } totalTime = 0; while (totalTime < MaxTime && !cancelEvent.WaitOne(0, false) && !doneEvent.WaitOne(0, false) && !mre.WaitOne(10, false)) { totalTime += 10; } if (totalTime >= MaxTime || cancelEvent.WaitOne(0, false) || doneEvent.WaitOne(0, false)) { APILogger.Log("Diagnostics::Exiting early due to timeout or user cancel"); diagnosticsService.ForceCancel(); Thread.Sleep(100); cancelEvent.Set(); return; } //warn if there are any failed units if (failedUnits.Any()) { var msgs = new List(); foreach (var failedUnit in failedUnits) { msgs.Add(string.Format(StringResources.DiagnosticsFailed_Unit, failedUnit.Item1.SerialNumber, failedUnit.Item2)); } //notify consumer that work is done and it can stop waiting workEventDone.Set(); } } } } } }