/* * DTS.Slice.Control.Event.cs * * Copyright © 2009 * Diversified Technical Systems, Inc. * All Rights Reserved */ using System; using System.Collections.Generic; using System.Diagnostics; using DTS.Common.DASResource; using DTS.Common.SerializationPlus; using DTS.DASLib.Service; using DTS.Serialization; using DTS.Common.Utilities; using DTS.Common.Utilities.DotNetProgrammingConstructs; using DTS.Common.Utilities.Logging; using DTS.Common.Enums.Sensors; using System.Linq; using DTS.Common.Enums.DASFactory; using DTS.Common.Interface.DASFactory.Config; using DTS.Common.Interface.DASFactory; namespace DTS.Slice.Control { /// /// Slice control representation of all information related to a slice event. /// public partial class Event : Exceptional, Test.IConvertable { /// /// Get/set the Id for this event. /// public string Id { get => _Id.Value; set => _Id.Value = value; } private readonly Property _Id = new Property("DTS.Slice.Control.Event.Id", null, false); /// /// Get/set the description for this event. /// public string Description { get => _Description.Value; set => _Description.Value = value; } private readonly Property _Description = new Property("DTS.Slice.Control.Event.Description", null, false); //FB 18312 added event number /// /// Get/set the EventNumber for this event. /// public int EventNumber { get => _EventNumber.Value; set => _EventNumber.Value = value; } private readonly Property _EventNumber = new Property("DTS.Slice.Control.Event.EventNumber", 0, false); /// /// The globally unique identification string for this event. /// public Guid Guid { get => _Guid.Value; set => _Guid.Value = value; } private readonly Property _Guid = new Property(typeof(Event).Namespace + ".Event.Guid", new Guid("00000000-0000-0000-0000-000000000000"), true); /// /// The global Fault Flags for this event. /// public UInt16 FaultFlags { get => _FaultFlags.Value; set => _FaultFlags.Value = value; } private readonly Property _FaultFlags = new Property(typeof(Event).Namespace + ".Event.FaultFlags", 0, true); /// /// the global extended fault flags for this event /// public uint ExtendedFaultFlags1 { get => _ExtendedFaultFlags1.Value; set => _ExtendedFaultFlags1.Value = value; } private readonly Property _ExtendedFaultFlags1 = new Property(typeof(Event).Namespace + ".Event.ExtendedFaultFlags1", 0, true); public uint ExtendedFaultFlags2 { get => _ExtendedFaultFlags2.Value; set => _ExtendedFaultFlags2.Value = value; } private readonly Property _ExtendedFaultFlags2 = new Property(typeof(Event).Namespace + ".Event.ExtendedFaultFlags2", 0, true); public uint ExtendedFaultFlags3 { get => _ExtendedFaultFlags3.Value; set => _ExtendedFaultFlags3.Value = value; } private readonly Property _ExtendedFaultFlags3 = new Property(typeof(Event).Namespace + ".Event.ExtendedFaultFlags3", 0, true); public uint ExtendedFaultFlags4 { get => _ExtendedFaultFlags4.Value; set => _ExtendedFaultFlags4.Value = value; } private readonly Property _ExtendedFaultFlags4 = new Property(typeof(Event).Namespace + ".Event.ExtendedFaultFlags4", 0, true); /// /// Get the date of this object's creation. Expected to be populated with the creation /// date of the serialization from which this object has been generated. /// public DateTime InceptionDate { get => _InceptionDate.Value; private set => _InceptionDate.Value = value; } private readonly Property _InceptionDate = new Property( typeof(Event).Namespace + ".Event.InceptionDate", DateTime.Now, false ); /// /// Get/set this event's list of s. /// public List Modules { get => _Modules.Value; set => _Modules.Value = value; } private readonly Property> _Modules = new Property>("DTS.Slice.Control.Event.Modules", null, false); /// /// Get/set this event's list of calculatedchannels/>s. /// public List CalculatedChannels { get => _CalculatedChannels.Value; set => _CalculatedChannels.Value = value; } private readonly Property> _CalculatedChannels = new Property>("DTS.Slice.Control.Event.CalculatedChannels", null, false); /// /// Initialize an instance of the DTS.Slice.Control.Event class. /// public Event() { } /// /// Initialize an instance of the DTS.Slice.Control.Event class. /// /// /// /// The ID of this event. /// /// /// /// The description of this event. /// /// public Event(string id, string description) { try { Id = id; Description = description; } catch (System.Exception ex) { throw new Exception( string.Format( Strings.DTS_Slice_Control_Event_ConstructionFailedString, GetType().FullName), ex); } } /// /// Initialize an instance of the DTS.Slice.Control.Event class. /// /// /// /// The to initialize this object with. /// /// public Event(Test test, Test.ReportErrors reportErrors) { try { FromDtsSerializationTest(test, reportErrors); } catch (System.Exception ex) { APILogger.Log(ex); throw; } } /// /// Initialize an instance of the DTS.Slice.Control.Event class. /// /// /// /// The ID of this event. /// /// /// /// The description of this event. /// /// /// /// The list of s associated with this event. /// /// public Event(string id, string description, List modules) { try { Id = id; Description = description; Modules = modules; } catch (System.Exception ex) { throw new Exception( string.Format( Strings.DTS_Slice_Control_Event_ConstructionFailedString, GetType().FullName), ex); } } // xxx Event ID, start sample, stop sample, // xxx Keep a double hash of DAS->Channel... looks like it would probably bypass the // module concept since the API just returns based on // Also need to add thread protection. // xxx Can we set locks in the property accessors for this stuff? At least for the // data methods... should the constructor need just an enclosure, or a lambda that // takes a dictionary lookup... /// /// Get a named-DAS/numbered-module accessor to this Event's modules. /// public DasModuleAccessor DasModules { get => _DasModules.Value; private set => _DasModules.Value = value; } private readonly Property _DasModules = new Property( typeof(Event).Namespace + ".Event.DasModules", new DasModuleAccessor(), true ); /// /// Get a named-DAS/numbered-channel accessor to this Event's channels. /// public DasChannelAccessor DasChannels { get => _DasChannels.Value; private set => _DasChannels.Value = value; } private readonly Property _DasChannels = new Property( typeof(Event).Namespace + ".Event.DasChannels", new DasChannelAccessor(), true ); /// /// Get a named-DAS/numbered-module/numbered-channel accessor to this Event's channels. /// public DasModuleChannelAccessor DasModuleChannels { get => _DasModuleChannels.Value; private set => _DasModuleChannels.Value = value; } private readonly Property _DasModuleChannels = new Property( typeof(Event).Namespace + ".Event.DasModules", new DasModuleChannelAccessor(), true ); public static bool IsG5(IDASCommunication idas) { return idas.SerialNumber.StartsWith("5M"); } public static bool IsSlice6DBModule(Module module) { if (null != module && null != module.Description && module.Description.ToLower() == DTS.Common.Constants.DUMMY_MOD_DESCRIP_S6DB) { return true; } return false; } public static bool IsPowerProModule(Module module) { if (null != module && null != module.Description && module.Description.ToLower() == DTS.Common.Constants.DUMMY_MOD_DESCRIP_POWERPRO) { return true; } return false; } const string ClockModule = "clock module"; public static bool IsClockModule(Module module) { if (null != module?.Description && module.Description.ToLower() == ClockModule) { return true; } return false; } const string StreamInModule = "stream in module"; public static bool IsStreamInModule(Module module) { if (null != module?.Description && module.Description.ToLower() == StreamInModule) { return true; } return false; } /// /// Initialize an instance of the DTS.Slice.Control.Event class. /// /// /// /// A list of connected devices that will be used /// to determine the dimensions of the Event's internal structures. /// /// public Event(List dases, EventInfoAggregate info) { try { if (null == dases) throw new ArgumentNullException(Strings.DTS_Slice_Control_Event_Event_NullDasListString); if (0 >= dases.Count) throw new Exception(Strings.DTS_Slice_Control_Event_Event_EmptyDasListString); Modules = new List(); var dasTestInformations = new Dictionary(); var absoluteChannelNumber = 0; foreach (var das in dases) { var eventIndex = info.GetEventIndex(das); if (null == das.SerialNumber) throw new UserException("Slice API returned no serial number for passed DAS"); // (connect string: " + ( null != das.DASInfo. das.ConnectString ? das.ConnectString : "" ) + ")" ); if (null == das.EventInfo) throw new UserException("Slice API returned no EventInfo for passed DAS"); if (null == das.EventInfo.Events[eventIndex]) throw new UserException("Slice API returned no configuration data for passed DAS"); // \"" + ( null != das.Comm.SensorSerialNumber ? das.Comm.SensorSerialNumber : "" ) + "\"" ); var eventInfo = das.EventInfo.Events[eventIndex]; dasTestInformations.Add(das.SerialNumber, new TestInformation(eventInfo.TestID, eventInfo.Description ?? "")); DasModules.Add(das.SerialNumber, new List()); DasChannels.Add(das.SerialNumber, new List()); DasModuleChannels.Add(das.SerialNumber, new ModuleChannelAccessor()); if (null != eventInfo.Modules) { var moduleList = new List(eventInfo.Modules); foreach (var iDASModule in moduleList) { var dasModule = (DASModule)iDASModule; //Add entries for empty slots in a TDAS rack while (dasModule.ModuleArrayIndex > DasModules[das.SerialNumber].Count) { Module emptyModule; Modules.Add(emptyModule = new Module(this)); DasModules[das.SerialNumber].Add(emptyModule); } Module nextModule; Modules.Add(nextModule = new Module(this)); DasModules[das.SerialNumber].Add(nextModule); DasModuleChannels[das.SerialNumber].Add(dasModule.ModuleArrayIndex, new ChannelAccessor()); // I think this can be done for everyone (and is the right thing), but for now make it TDAS PRO Rack specific if (das is EthernetTDAS) { // We want module to be the actual SIM or TOM serial number, not the rack serial number nextModule.DasSerialNumber = das.DASInfo.Modules[dasModule.ModuleArrayIndex].SerialNumber; } else { nextModule.DasSerialNumber = das.SerialNumber; } // This is an important condition if they module property population that occurs after // this constructor using the dasModules object is going to line thing up right. Debug.Assert(DasModules[das.SerialNumber].Count - 1 == dasModule.ModuleArrayIndex); // Maybe these should be getting populated later on using the SetPropertiesFrom(x) after // the query download successfully returns...? nextModule.Description = dasModule.Description; nextModule.AaFilterRateHz = dasModule.AAFilterRateHz; nextModule.Number = dasModule.ModuleArrayIndex; nextModule.NumberOfSamples = dasModule.NumberOfSamples; nextModule.RequestedPostTriggerSeconds = dasModule.RequestedPostTriggerSeconds; nextModule.RequestedPreTriggerSeconds = dasModule.RequestedPreTriggerSeconds; nextModule.PostTriggerSeconds = dasModule.PostTriggerSeconds; nextModule.PreTriggerSeconds = dasModule.PreTriggerSeconds; nextModule.RecordingMode = dasModule.RecordingMode; nextModule.SampleRateHz = dasModule.SampleRateHz; nextModule.StartRecordSampleNumber = dasModule.StartRecordSampleNumber; nextModule.BaseSerialNumber = dasModule.OwningDAS.SerialNumber; nextModule.StartRecordTimestampSec = dasModule.StartRecordTimestampSec; nextModule.StartRecordTimestampNanoSec = dasModule.StartRecordTimestampNanoSec; nextModule.TriggerTimestampSec = dasModule.TriggerTimestampSec; nextModule.TriggerTimestampNanoSec = dasModule.TriggerTimestampNanoSec; nextModule.PTPMasterSync = dasModule.PTPMasterSync; if (dasModule.UseForTiltCalculation) { nextModule.SystemID = dasModule.SystemID; nextModule.SystemLocation = dasModule.SystemLocation; nextModule.TargetAxisOne = dasModule.TargetAxisOne; nextModule.TargetAxisTwo = dasModule.TargetAxisTwo; switch (dasModule.TiltAxes) { case DFConstantsAndEnums.TiltAxes.IXIYIZ: case DFConstantsAndEnums.TiltAxes.IXIYZ: case DFConstantsAndEnums.TiltAxes.IXYIZ: case DFConstantsAndEnums.TiltAxes.IXYZ: case DFConstantsAndEnums.TiltAxes.XIYIZ: case DFConstantsAndEnums.TiltAxes.XIYZ: case DFConstantsAndEnums.TiltAxes.XYIZ: case DFConstantsAndEnums.TiltAxes.XYZ: switch (dasModule.AxisIgnored) { case 1: nextModule.TiltSensorAxisXDegreesPre = double.NaN; nextModule.TargetAxisX = double.NaN; nextModule.TiltSensorAxisYDegreesPre = dasModule.TiltSensorAxisYDegreesPre; nextModule.TargetAxisY = dasModule.TargetAxisOne; nextModule.TiltSensorAxisZDegreesPre = dasModule.TiltSensorAxisZDegreesPre; nextModule.TargetAxisZ = dasModule.TargetAxisTwo; break; case 2: nextModule.TiltSensorAxisXDegreesPre = dasModule.TiltSensorAxisXDegreesPre; nextModule.TargetAxisX = dasModule.TargetAxisOne; nextModule.TiltSensorAxisYDegreesPre = double.NaN; nextModule.TargetAxisY = double.NaN; nextModule.TiltSensorAxisZDegreesPre = dasModule.TiltSensorAxisZDegreesPre; nextModule.TargetAxisZ = dasModule.TargetAxisTwo; break; case 3: nextModule.TiltSensorAxisXDegreesPre = dasModule.TiltSensorAxisXDegreesPre; nextModule.TargetAxisX = dasModule.TargetAxisOne; nextModule.TiltSensorAxisYDegreesPre = dasModule.TiltSensorAxisYDegreesPre; nextModule.TargetAxisY = dasModule.TargetAxisTwo; nextModule.TiltSensorAxisZDegreesPre = double.NaN; nextModule.TargetAxisZ = double.NaN; break; } break; case DFConstantsAndEnums.TiltAxes.IXIZIY: case DFConstantsAndEnums.TiltAxes.IXIZY: case DFConstantsAndEnums.TiltAxes.IXZIY: case DFConstantsAndEnums.TiltAxes.IXZY: case DFConstantsAndEnums.TiltAxes.XIZIY: case DFConstantsAndEnums.TiltAxes.XIZY: case DFConstantsAndEnums.TiltAxes.XZIY: case DFConstantsAndEnums.TiltAxes.XZY: switch (dasModule.AxisIgnored) { case 1: nextModule.TiltSensorAxisXDegreesPre = double.NaN; nextModule.TargetAxisX = double.NaN; nextModule.TiltSensorAxisZDegreesPre = dasModule.TiltSensorAxisZDegreesPre; nextModule.TargetAxisZ = dasModule.TargetAxisOne; nextModule.TiltSensorAxisYDegreesPre = dasModule.TiltSensorAxisYDegreesPre; nextModule.TargetAxisY = dasModule.TargetAxisTwo; break; case 2: nextModule.TiltSensorAxisXDegreesPre = dasModule.TiltSensorAxisXDegreesPre; nextModule.TargetAxisX = dasModule.TargetAxisOne; nextModule.TiltSensorAxisZDegreesPre = double.NaN; nextModule.TargetAxisZ = double.NaN; nextModule.TiltSensorAxisYDegreesPre = dasModule.TiltSensorAxisYDegreesPre; nextModule.TargetAxisY = dasModule.TargetAxisTwo; break; case 3: nextModule.TiltSensorAxisXDegreesPre = dasModule.TiltSensorAxisXDegreesPre; nextModule.TargetAxisX = dasModule.TargetAxisOne; nextModule.TiltSensorAxisZDegreesPre = dasModule.TiltSensorAxisZDegreesPre; nextModule.TargetAxisZ = dasModule.TargetAxisTwo; nextModule.TiltSensorAxisYDegreesPre = double.NaN; nextModule.TargetAxisY = double.NaN; break; } break; case DFConstantsAndEnums.TiltAxes.IYIXIZ: case DFConstantsAndEnums.TiltAxes.IYIXZ: case DFConstantsAndEnums.TiltAxes.IYXIZ: case DFConstantsAndEnums.TiltAxes.IYXZ: case DFConstantsAndEnums.TiltAxes.YIXIZ: case DFConstantsAndEnums.TiltAxes.YIXZ: case DFConstantsAndEnums.TiltAxes.YXIZ: case DFConstantsAndEnums.TiltAxes.YXZ: switch (dasModule.AxisIgnored) { case 1: nextModule.TiltSensorAxisYDegreesPre = double.NaN; nextModule.TargetAxisY = double.NaN; nextModule.TiltSensorAxisXDegreesPre = dasModule.TiltSensorAxisXDegreesPre; nextModule.TargetAxisX = dasModule.TargetAxisOne; nextModule.TiltSensorAxisZDegreesPre = dasModule.TiltSensorAxisZDegreesPre; nextModule.TargetAxisZ = dasModule.TargetAxisTwo; break; case 2: nextModule.TiltSensorAxisYDegreesPre = dasModule.TiltSensorAxisYDegreesPre; nextModule.TargetAxisY = dasModule.TargetAxisOne; nextModule.TiltSensorAxisXDegreesPre = double.NaN; nextModule.TargetAxisX = double.NaN; nextModule.TiltSensorAxisZDegreesPre = dasModule.TiltSensorAxisZDegreesPre; nextModule.TargetAxisZ = dasModule.TargetAxisTwo; break; case 3: nextModule.TiltSensorAxisYDegreesPre = dasModule.TiltSensorAxisYDegreesPre; nextModule.TargetAxisY = dasModule.TargetAxisOne; nextModule.TiltSensorAxisXDegreesPre = dasModule.TiltSensorAxisXDegreesPre; nextModule.TargetAxisX = dasModule.TargetAxisTwo; nextModule.TiltSensorAxisZDegreesPre = double.NaN; nextModule.TargetAxisZ = double.NaN; break; } break; case DFConstantsAndEnums.TiltAxes.IYIZIX: case DFConstantsAndEnums.TiltAxes.IYIZX: case DFConstantsAndEnums.TiltAxes.IYZIX: case DFConstantsAndEnums.TiltAxes.IYZX: case DFConstantsAndEnums.TiltAxes.YIZIX: case DFConstantsAndEnums.TiltAxes.YIZX: case DFConstantsAndEnums.TiltAxes.YZIX: case DFConstantsAndEnums.TiltAxes.YZX: switch (dasModule.AxisIgnored) { case 1: nextModule.TiltSensorAxisYDegreesPre = double.NaN; nextModule.TargetAxisY = double.NaN; nextModule.TiltSensorAxisZDegreesPre = dasModule.TiltSensorAxisZDegreesPre; nextModule.TargetAxisZ = dasModule.TargetAxisOne; nextModule.TiltSensorAxisXDegreesPre = dasModule.TiltSensorAxisXDegreesPre; nextModule.TargetAxisX = dasModule.TargetAxisTwo; break; case 2: nextModule.TiltSensorAxisYDegreesPre = dasModule.TiltSensorAxisYDegreesPre; nextModule.TargetAxisY = dasModule.TargetAxisOne; nextModule.TiltSensorAxisZDegreesPre = double.NaN; nextModule.TargetAxisZ = double.NaN; nextModule.TiltSensorAxisXDegreesPre = dasModule.TiltSensorAxisXDegreesPre; nextModule.TargetAxisX = dasModule.TargetAxisTwo; break; case 3: nextModule.TiltSensorAxisYDegreesPre = dasModule.TiltSensorAxisYDegreesPre; nextModule.TargetAxisY = dasModule.TargetAxisOne; nextModule.TiltSensorAxisZDegreesPre = dasModule.TiltSensorAxisZDegreesPre; nextModule.TargetAxisZ = dasModule.TargetAxisTwo; nextModule.TiltSensorAxisXDegreesPre = double.NaN; nextModule.TargetAxisX = double.NaN; break; } break; case DFConstantsAndEnums.TiltAxes.IZIXIY: case DFConstantsAndEnums.TiltAxes.IZIXY: case DFConstantsAndEnums.TiltAxes.IZXIY: case DFConstantsAndEnums.TiltAxes.IZXY: case DFConstantsAndEnums.TiltAxes.ZIXIY: case DFConstantsAndEnums.TiltAxes.ZIXY: case DFConstantsAndEnums.TiltAxes.ZXIY: case DFConstantsAndEnums.TiltAxes.ZXY: switch (dasModule.AxisIgnored) { case 1: nextModule.TiltSensorAxisZDegreesPre = double.NaN; nextModule.TargetAxisZ = double.NaN; nextModule.TiltSensorAxisXDegreesPre = dasModule.TiltSensorAxisXDegreesPre; nextModule.TargetAxisX = dasModule.TargetAxisOne; nextModule.TiltSensorAxisYDegreesPre = dasModule.TiltSensorAxisYDegreesPre; nextModule.TargetAxisY = dasModule.TargetAxisTwo; break; case 2: nextModule.TiltSensorAxisZDegreesPre = dasModule.TiltSensorAxisZDegreesPre; nextModule.TargetAxisZ = dasModule.TargetAxisOne; nextModule.TiltSensorAxisXDegreesPre = double.NaN; nextModule.TargetAxisX = double.NaN; nextModule.TiltSensorAxisYDegreesPre = dasModule.TiltSensorAxisYDegreesPre; nextModule.TargetAxisY = dasModule.TargetAxisTwo; break; case 3: nextModule.TiltSensorAxisZDegreesPre = dasModule.TiltSensorAxisZDegreesPre; nextModule.TargetAxisZ = dasModule.TargetAxisOne; nextModule.TiltSensorAxisXDegreesPre = dasModule.TiltSensorAxisXDegreesPre; nextModule.TargetAxisX = dasModule.TargetAxisTwo; nextModule.TiltSensorAxisYDegreesPre = double.NaN; nextModule.TargetAxisY = double.NaN; break; } break; case DFConstantsAndEnums.TiltAxes.IZIYIX: case DFConstantsAndEnums.TiltAxes.IZIYX: case DFConstantsAndEnums.TiltAxes.IZYIX: case DFConstantsAndEnums.TiltAxes.IZYX: case DFConstantsAndEnums.TiltAxes.ZIYIX: case DFConstantsAndEnums.TiltAxes.ZIYX: case DFConstantsAndEnums.TiltAxes.ZYIX: case DFConstantsAndEnums.TiltAxes.ZYX: switch (dasModule.AxisIgnored) { case 1: nextModule.TiltSensorAxisZDegreesPre = double.NaN; nextModule.TargetAxisZ = double.NaN; nextModule.TiltSensorAxisYDegreesPre = dasModule.TiltSensorAxisYDegreesPre; nextModule.TargetAxisY = dasModule.TargetAxisOne; nextModule.TiltSensorAxisXDegreesPre = dasModule.TiltSensorAxisXDegreesPre; nextModule.TargetAxisX = dasModule.TargetAxisTwo; break; case 2: nextModule.TiltSensorAxisZDegreesPre = dasModule.TiltSensorAxisZDegreesPre; nextModule.TargetAxisZ = dasModule.TargetAxisOne; nextModule.TiltSensorAxisYDegreesPre = double.NaN; nextModule.TargetAxisY = double.NaN; nextModule.TiltSensorAxisXDegreesPre = dasModule.TiltSensorAxisXDegreesPre; nextModule.TargetAxisX = dasModule.TargetAxisTwo; break; case 3: nextModule.TiltSensorAxisZDegreesPre = dasModule.TiltSensorAxisZDegreesPre; nextModule.TargetAxisZ = dasModule.TargetAxisOne; nextModule.TiltSensorAxisYDegreesPre = dasModule.TiltSensorAxisYDegreesPre; nextModule.TargetAxisY = dasModule.TargetAxisTwo; nextModule.TiltSensorAxisXDegreesPre = double.NaN; nextModule.TargetAxisX = double.NaN; break; } break; } } else { nextModule.TiltSensorAxisXDegreesPre = dasModule.TiltSensorAxisXDegreesPre; nextModule.TiltSensorAxisYDegreesPre = dasModule.TiltSensorAxisYDegreesPre; nextModule.TiltSensorAxisZDegreesPre = dasModule.TiltSensorAxisZDegreesPre; nextModule.TiltSensorAxisXDegreesPost = dasModule.TiltSensorAxisXDegreesPost; nextModule.TiltSensorAxisYDegreesPost = dasModule.TiltSensorAxisYDegreesPost; nextModule.TiltSensorAxisZDegreesPost = dasModule.TiltSensorAxisZDegreesPost; } nextModule.TemperatureLocation1Pre = dasModule.TemperatureLocation1Pre; nextModule.TemperatureLocation2Pre = dasModule.TemperatureLocation2Pre; nextModule.TemperatureLocation3Pre = dasModule.TemperatureLocation3Pre; nextModule.TemperatureLocation4Pre = dasModule.TemperatureLocation4Pre; nextModule.TemperatureLocation1Post = dasModule.TemperatureLocation1Post; nextModule.TemperatureLocation2Post = dasModule.TemperatureLocation2Post; nextModule.TemperatureLocation3Post = dasModule.TemperatureLocation3Post; nextModule.TemperatureLocation4Post = dasModule.TemperatureLocation4Post; nextModule.InputVoltage = dasModule.InputVoltage; nextModule.BatteryVoltage = dasModule.BatteryVoltage; nextModule.Channels = new List(); if (Array.TrueForAll(dasModule.Channels, ch => ch.ConfigurationMode == DFConstantsAndEnums.ConfigMode.Clock)) { nextModule.Description = ClockModule; } if (Array.TrueForAll(dasModule.Channels, ch => ch.ConfigurationMode == DFConstantsAndEnums.ConfigMode.StreamIn)) { nextModule.Description = StreamInModule; } var moduleType = dasModule.GetType(); if ((null != dasModule.Channels) && (dasModule.Channels.Length > 0) && (Array.Exists(dasModule.Channels, x => x.ConfigurationMode != DFConstantsAndEnums.ConfigMode.DummyArm) || IsG5(das)) // How could a SLICE be a G5? Is this the checking serial numbers for SLICE G5s? ) { var list = new List(dasModule.Channels); foreach (var idasChannel in list) { var dasChannel = (DASChannel)idasChannel; Module.Channel nextChannel = Module.Channel.CreateChannel(dasChannel, nextModule, absoluteChannelNumber++); nextChannel.IsSupersampled = dasModule.IsEmbedded(); nextChannel.UseEUScaler = dasModule.IsEmbedded(); nextChannel.UnsupersampledSampleRateHz = dasModule.IsEmbedded() && dasModule.ModuleArrayIndex < dasModule.EmbeddedSampleRateHz.Length ? dasModule.EmbeddedSampleRateHz[dasModule.ModuleArrayIndex] : 0; nextModule.Channels.Add(nextChannel); DasModuleChannels[das.SerialNumber][dasModule.ModuleArrayIndex].Add(dasChannel.ModuleChannelNumber, nextChannel); nextChannel.Number = dasChannel.ModuleChannelNumber; nextChannel.Start = dasChannel.EventStartTime; //Debug.Assert( das.SensorSerialNumber.Equals( dasModule.OwningDAS.SensorSerialNumber, StringComparison.OrdinalIgnoreCase ) ); //if ( null == das.Comm.ChannelDiagnosticsResults ) // throw new DTS.Slice.Control.Event.Exception( "no diagnostics results were received from the API for module " + nextModule.Number.ToString( ) + ", channel " + nextChannel.Number.ToString( ) ); //else { nextChannel.UnfilteredData = new List(); nextChannel.UnfilteredAlternateData = !string.IsNullOrWhiteSpace(nextChannel.LinearSensorCalibration) ? new List() : null; DasChannels[das.SerialNumber].Add(nextChannel); } } } } } } string testId = null; string testDescription = null; foreach (var dasId in dasTestInformations.Keys) { // // Walk through the list and verify that all of the test ID and description // strings are the same. // var newTestId = dasTestInformations[dasId].Id; if (null != testId && !testId.Equals(newTestId, StringComparison.OrdinalIgnoreCase)) { if (!newTestId.Equals(DFConstantsAndEnums.MADEUPEVENT_TESTID) && !testId.Equals(DFConstantsAndEnums.MADEUPEVENT_TESTID)) { throw new Exception( string.Format( Strings.DTS_Slice_Control_Event_Event_DASTestIdMismatchString, testId, dasId, newTestId)); } } if (!newTestId.Equals(DFConstantsAndEnums.MADEUPEVENT_TESTID)) { testId = newTestId; } var newTestDescription = dasTestInformations[dasId].Description; if (null != testDescription && !testDescription.Equals(newTestDescription, StringComparison.OrdinalIgnoreCase)) { /*throw new Exception( string.Format( Properties.Resources.DTS_Slice_Control_Event_Event_DASTestDescriptionMismatchString, testDescription, dasId, newTestDescription));*/ } else { testDescription = newTestDescription; } } if (null == testId) { testId = "Empty"; } if (null == testDescription) { testDescription = ""; } if (null == testId || null == testDescription) throw new Exception(Strings.DTS_Slice_Control_Event_Event_FailedToDetermineIdOrDescriptionFromConfigurationString); Id = testId; Description = testDescription; } catch (System.Exception ex) { throw new Exception( string.Format( Strings.DTS_Slice_Control_Event_ConstructionFailedString, GetType().FullName), ex); } } private bool IsTom(DASModule module) { try { if (module.SerialNumber().ToLower().Contains("tom")) { return true; } if (null != module.Channels && module.Channels.Length > 0) { if (module.Channels[0] is OutputSquibChannel) { return true; } } } catch (System.Exception ex) { APILogger.Log("problem getting serial number", ex); } return false; } /// /// Get the highest absolute channel number currently in this event. /// public int LastAbsoluteChannelNumberInEvent { get { try { var highestAbsoluteChannelNumberFound = -1; foreach (var module in Modules) foreach (var channel in module.Channels) if (channel.AbsoluteNumber > highestAbsoluteChannelNumberFound) highestAbsoluteChannelNumberFound = channel.AbsoluteNumber; //if ( highestAbsoluteChannelNumberFound < 0 ) // throw new Event.Exception( "no absolute channel numbers exist within this event" ); return highestAbsoluteChannelNumberFound; } catch (System.Exception ex) { throw new Exception("encountered problem getting last absolute channel number in event", ex); } } } /// /// Get the per-sample threshold that when exceeded by the total basic data /// volume of this event results in Event.IsTooLargeFor32BitVisualization to return true. /// /// /// /// Justification for the current default value: /// With filter caching disabled, the memory usage is AT LEAST 76.4 bytes/sample, broken down thus: /// /// Event structure: /// 1 sample needs 2 bytes ADC representation, /// 8 bytes mV representation, /// 8 bytes EU representation. Total: 18 bytes /// + /// Filtering procedure: 1 sample needs 8 bytes for initial double-sized "ToArray", /// and 1.1 * ( 8 * 3 ) bytes for the three 5% padded front & end processing arrays /// inside the algorithm. Total: 34.4 bytes /// + /// Viewer memory: 1 sample needs 8 bytes for the internal viewer representation /// (at a minimum) + ( 2 * 8 ) bytes for the two arrays required to feed the viewer /// interface. Total: 24 bytes /// /// = 76.5 bytes/sample. /// /// Not sure how much memory the rest of SliceWARE takes when up and running, but using this number /// we seem to be okay if we stay below 1GB, but run into trouble when we go over if we first do other /// things that might leave things around in memory, i.e., download. The three sections above pretty /// much stack while loading a test into the viewer. /// /// private static readonly double MaximumVisualizationBytesPerSample = 2D; public double TooLargeFor32BitVisualizationBytesPerSampleThreshold { get => _TooLargeFor32BitVisualizationBytesPerSampleThreshold.Value; private set => _TooLargeFor32BitVisualizationBytesPerSampleThreshold.Value = value; } private readonly Property _TooLargeFor32BitVisualizationBytesPerSampleThreshold = new Property( typeof(Event).FullName + ".TooLargeFor32BitVisualizationBytesPerSampleThreshold", MaximumVisualizationBytesPerSample, true ); /// /// Get value indicating whether or not this event has more combined data than a 32 bit /// system could handle all at once. /// public bool IsTooLargeFor32BitVisualization { get { try { ulong totalChannelDataCount = 0; foreach (var module in Modules) { foreach (var channel in module.Channels) { if (channel.UnfilteredData is Serialization.TDAS.File.PersistentChannel persistentChannel) { totalChannelDataCount += persistentChannel.NumberOfSamples; } else { totalChannelDataCount += ((Serialization.SliceRaw.File.PersistentChannel)channel.UnfilteredData) .NumberOfSamples; } } } return (totalChannelDataCount * TooLargeFor32BitVisualizationBytesPerSampleThreshold) > 0x7FFFFFFF; } catch (System.Exception ex) { throw new Exception("encountered problem determining whether or not this event's combined data is too big for 32-bit visualization", ex); } } } /// /// Get value indicating whether or not this event contains channels with average over /// time zero methods, but have specified an invalid averaging window. /// public bool ContainsChannelsActiveInvalidZeroingWindows => ChannelsWithActiveInvalidZeroingWindows.Count > 0; /// /// we initialize the window average to short min value, which is a valid data value but probably means bad things /// if your window average is legitimately short min value ... /// private const short InvalidWindowAverage = short.MinValue; /// /// Get the list of all s that with average over time /// zero method set, but have specified an invalid averaging window. /// public List ChannelsWithActiveInvalidZeroingWindows { get { try { var invalidZeroWindowChannels = new List(); foreach (var module in Modules) foreach (var channel in module.Channels) if (channel is Module.AnalogInputChannel analogChannel) { if (ZeroMethodType.AverageOverTime == analogChannel.ZeroMethod) { //if we have a stored window average for the channel, well then it's definitely not an invalid window average ... if (analogChannel.WindowAverageADC != InvalidWindowAverage) { continue; } //otherwise check to see if we have an invalid window average var windowStart = ((analogChannel.ParentModule.TriggerSampleNumbers.Count > 0) ? analogChannel.ParentModule.TriggerSampleNumbers[0] : 0) + (analogChannel.ZeroAverageWindow.Begin * analogChannel.ParentModule.SampleRateHz); var windowEnd = ((analogChannel.ParentModule.TriggerSampleNumbers.Count > 0) ? analogChannel.ParentModule.TriggerSampleNumbers[0] : 0) + (analogChannel.ZeroAverageWindow.End * analogChannel.ParentModule.SampleRateHz); if (0 > windowStart || 0 > windowEnd) { invalidZeroWindowChannels.Add(analogChannel); } else { var dataStart = analogChannel.ParentModule.StartRecordSampleNumber; var dataEnd = dataStart + analogChannel.ParentModule.NumberOfSamples; if (dataStart > windowStart || windowStart > dataEnd) { invalidZeroWindowChannels.Add(analogChannel); } else if (dataEnd < windowEnd || windowEnd < dataStart) { invalidZeroWindowChannels.Add(analogChannel); } } } } return invalidZeroWindowChannels; } catch (System.Exception ex) { throw new Exception("encountered problem building list of event channels with active invalid zeroing windows", ex); } } } private bool IsEmptyModule(Module module) { foreach (var channel in module.Channels) { if (channel.IsConfigured || !IsDummyChannel(channel)) { return false; } } return true; } private void PurgeUnconfiguredChannels() { foreach (var module in Modules) { module.Channels.RemoveAll(channel => !channel.IsConfigured || IsDummyChannel(channel)); } } /// /// Convert this object to a DTS.Serialization.Test. /// /// /// /// A equivalent to this object. /// /// public Test ToDtsSerializationTest() { try { // // Create a test to embody the conversion and copy over all relevant // test data members. // var that = new Test(); PurgeUnconfiguredChannels(); that.Id = Id; that.Description = Description; that.EventNumber = EventNumber; that.Guid = Guid; that.FaultFlags = FaultFlags; that.ExtendedFaultFlags1 = ExtendedFaultFlags1; that.ExtendedFaultFlags2 = ExtendedFaultFlags2; that.ExtendedFaultFlags3 = ExtendedFaultFlags3; that.ExtendedFaultFlags4 = ExtendedFaultFlags4; that.Modules = new List(); //set the test inception date to the timestamp of the test //15266 Can we set the date/time of the data collection when exporting CSV data? that.InceptionDate = InceptionDate; foreach (var thisModule in Modules) { //Normally, we don't care about empty modules (no data channels), but if it's //a SLICE6 Distributor (a null ParentEvent), we want to output a module element to the .dts file. if (IsEmptyModule(thisModule) && !IsSlice6DBModule(thisModule) && !IsPowerProModule(thisModule)) { continue; } //We do care about the timing data in clock modules, but do not want them output to the .dts file. if (IsClockModule(thisModule)) { continue; } //We do care about the saved stream data in streaming in modules, but do not want them output to the .dts file. if (IsStreamInModule(thisModule)) { continue; } // // Create a test module to embody each module conversion, and then copy // over all relevant module data members. // that.Modules.Add(thisModule.ToDtsSerializationTestModule(that)); } that.DasTimestamps = new List(); foreach (var thisClockModule in Modules.Where(mod => IsClockModule(mod))) { if (!that.DasTimestamps.Exists(stamp => stamp.BaseSerialNumber == thisClockModule.BaseSerialNumber)) { var newstamp = new Test.DasTimestamp(that) { BaseSerialNumber = thisClockModule.BaseSerialNumber, NumberOfSamples = thisClockModule.NumberOfSamples, NumberOfBitsPerSample = 8 * sizeof(ulong) }; that.DasTimestamps.Add(newstamp); } } return that; } catch (System.Exception ex) { throw new Exception("encountered problem converting " + GetType().FullName + " to " + typeof(Test).FullName, ex); } } /// /// Initialize this object from a DTS.Serialization.Test. /// /// /// /// A from which to initialize this object. /// /// public void FromDtsSerializationTest(Test that, Test.ReportErrors reportErrors) { try { if (null == that) throw new ArgumentNullException("cannot set this object's properties from null serialization test reference"); // // Create the Slice Control test that will be equivalent to the specified serialization // test and populate its relevant properties. // Id = that.Id; Description = that.Description; EventNumber = that.EventNumber; FaultFlags = that.FaultFlags; ExtendedFaultFlags1 = that.ExtendedFaultFlags1; ExtendedFaultFlags2 = that.ExtendedFaultFlags2; ExtendedFaultFlags3 = that.ExtendedFaultFlags3; ExtendedFaultFlags4 = that.ExtendedFaultFlags4; Guid = that.Guid; InceptionDate = that.InceptionDate; Modules = new List(); foreach (var thatModule in that.Modules) { // // Create a Slice Control module corresponding to the specified serialization module // and populate its relevant properties. // Modules.Add(new Module(thatModule, this, reportErrors)); } } catch (System.IO.InvalidDataException) { throw; } catch (System.Exception ex) { throw new Exception("encountered problem initializing " + GetType().FullName + " using " + typeof(Test).FullName, ex); } } /// /// Method to convert a DTS.Slice.Control.Event object to an equivalent DTS.Serialization.Test object. /// /// /// /// The to be converted. /// /// /// /// A that is equivalent to the specified Slice Control event. /// /// public static implicit operator Test(Event sliceControlEvent) { try { return sliceControlEvent.ToDtsSerializationTest(); } catch (System.Exception ex) { throw new Exception("encountered problem implicitly converting " + typeof(Event).FullName + " to " + typeof(Test).FullName, ex); } } /// /// this really belongs in the channel object, but for now just abstract the function out of /// where the logic is needed /// /// /// private bool IsDummyChannel(Module.Channel channel) { if (null != channel && channel.ChannelDescriptionString.ToLower() == "dummy arm channel") { return true; } return false; } /// /// Get/set the base serialization directory path for events. /// public static string BaseSerializationDirectory { get => _BaseSerializationDirectory.Value; set => _BaseSerializationDirectory.Value = value; } private static readonly Property _BaseSerializationDirectory = new Property( typeof(Event).Namespace + ".BaseSerializationDirectory", null, false ); /// /// Construct the serialization path for the specified event ID. /// /// /// /// The ID of the event whose serialization path is sought. /// /// /// /// The path for the specified event's serialization. /// /// public static string GetEventSerializationDirectory(string eventId) { try { return System.IO.Path.Combine(BaseSerializationDirectory, eventId); } catch (System.Exception ex) { //throw new ReviewForm.Exception("encountered problem getting target directory for test " + (null != eventId ? "\"" + eventId + "\"" : ""), ex); throw new Exception("encountered problem getting target directory for test " + (null != eventId ? "\"" + eventId + "\"" : ""), ex); } } /// /// Test the specified object for equality with this object. /// /// /// /// The to be tested for equality. /// /// /// /// true if the specified object has memberwise equality with /// this object; false otherwise. /// /// public override bool Equals(object obj) { try { return obj is Event that && Id.Equals(that.Id) && Description.Equals(that.Description) && Guid.Equals(that.Guid) && ModulesEquals(that.Modules) && FaultFlags.Equals(that.FaultFlags) && ExtendedFaultFlags1.Equals(that.ExtendedFaultFlags1) && ExtendedFaultFlags2.Equals(that.ExtendedFaultFlags2) && ExtendedFaultFlags3.Equals(that.ExtendedFaultFlags3) && ExtendedFaultFlags4.Equals(that.ExtendedFaultFlags4); } catch (System.Exception ex) { throw new Exception( string.Format( Strings.DTS_Slice_Control_Equals_ComparisonFailedString, null != obj ? "\"" + obj.ToString() + "\"" : Strings.DTS_Slice_Control_NullIndicatorString), ex); } } /// /// Test the specified object's module list for equality with this object's /// module list. /// /// /// /// The of objects to be /// compared for equality with this test's equivalent. /// /// /// /// true if the two lists contain equivalent-valued members; /// false otherwise. /// /// private bool ModulesEquals(List thoseModules) { try { if (Modules.Count != thoseModules.Count) return false; for (var i = 0; i < thoseModules.Count; i++) if (!Modules[i].Equals(thoseModules[i])) return false; return true; } catch (System.Exception ex) { throw new Exception(Strings.DTS_Slice_Control_Event_ModuleEquals_ComparisonFailedString, ex); } } /// /// Return the hash code for this object. /// /// /// /// The hash code for this object. /// /// public override int GetHashCode() { return base.GetHashCode(); } } }