887 lines
40 KiB
C#
887 lines
40 KiB
C#
/*
|
|
* 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.DASLib.Service;
|
|
using DTS.Serialization;
|
|
using DTS.Common.Utilities;
|
|
using DTS.Common.Utilities.DotNetProgrammingConstructs;
|
|
using DTS.Common.Utilities.Logging;
|
|
using DTS.Serialization.StringResources;
|
|
|
|
namespace DTS.Slice.Control
|
|
{
|
|
/// <summary>
|
|
/// Slice control representation of all information related to a slice event.
|
|
/// </summary>
|
|
public partial class Event
|
|
: Exceptional,
|
|
Test.IConvertable
|
|
{
|
|
/// <summary>
|
|
/// Get/set the <see cref="string"/> Id for this event.
|
|
/// </summary>
|
|
public string Id
|
|
{
|
|
get => _Id.Value;
|
|
set => _Id.Value = value;
|
|
}
|
|
private readonly Property<string> _Id = new Property<string>("DTS.Slice.Control.Event.Id", null, false);
|
|
|
|
/// <summary>
|
|
/// Get/set the description <see cref="string"/> for this event.
|
|
/// </summary>
|
|
public string Description
|
|
{
|
|
get => _Description.Value;
|
|
set => _Description.Value = value;
|
|
}
|
|
private readonly Property<string> _Description = new Property<string>("DTS.Slice.Control.Event.Description", null, false);
|
|
|
|
/// <summary>
|
|
/// The globally unique identification string for this event.
|
|
/// </summary>
|
|
public Guid Guid
|
|
{
|
|
get => _Guid.Value;
|
|
set => _Guid.Value = value;
|
|
}
|
|
private readonly Property<Guid> _Guid
|
|
= new Property<Guid>(typeof(Event).Namespace + ".Event.Guid", new Guid("00000000-0000-0000-0000-000000000000"), true);
|
|
|
|
/// <summary>
|
|
/// The global Fault Flags for this event.
|
|
/// </summary>
|
|
public UInt16 FaultFlags
|
|
{
|
|
get => _FaultFlags.Value;
|
|
set => _FaultFlags.Value = value;
|
|
}
|
|
private readonly Property<UInt16> _FaultFlags
|
|
= new Property<UInt16>(typeof(Event).Namespace + ".Event.FaultFlags", 0, true);
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public DateTime InceptionDate
|
|
{
|
|
get => _InceptionDate.Value;
|
|
private set => _InceptionDate.Value = value;
|
|
}
|
|
private readonly Property<DateTime> _InceptionDate
|
|
= new Property<DateTime>(
|
|
typeof(Event).Namespace + ".Event.InceptionDate",
|
|
DateTime.Now,
|
|
false
|
|
);
|
|
|
|
/// <summary>
|
|
/// Get/set this event's list of <see cref="DTS.Slice.Control.Event.Module"/>s.
|
|
/// </summary>
|
|
public List<Module> Modules
|
|
{
|
|
get => _Modules.Value;
|
|
set => _Modules.Value = value;
|
|
}
|
|
private readonly Property<List<Module>> _Modules = new Property<List<Module>>("DTS.Slice.Control.Event.Modules", null, false);
|
|
|
|
/// <summary>
|
|
/// Get/set this event's list of <see cref="DTS.Slice.Control.Event.CalculatedChannelsModule"/>s.
|
|
/// </summary>
|
|
public List<Module.Channel> CalculatedChannels
|
|
{
|
|
get => _CalculatedChannels.Value;
|
|
set => _CalculatedChannels.Value = value;
|
|
}
|
|
private readonly Property<List<Module.Channel>> _CalculatedChannels = new Property<List<Module.Channel>>("DTS.Slice.Control.Event.CalculatedChannels", null, false);
|
|
|
|
/// <summary>
|
|
/// Initialize an instance of the DTS.Slice.Control.Event class.
|
|
/// </summary>
|
|
public Event()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize an instance of the DTS.Slice.Control.Event class.
|
|
/// </summary>
|
|
///
|
|
/// <param name="id">
|
|
/// The <see cref="string"/> ID of this event.
|
|
/// </param>
|
|
///
|
|
/// <param name="description">
|
|
/// The <see cref="string"/> description of this event.
|
|
/// </param>
|
|
///
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize an instance of the DTS.Slice.Control.Event class.
|
|
|
|
/// </summary>
|
|
///
|
|
/// <param name="test">
|
|
/// The <see cref="DTS.Serialization.Test"/> to initialize this object with.
|
|
/// </param>
|
|
///
|
|
public Event(Test test, Test.ReportErrors reportErrors)
|
|
{
|
|
try
|
|
{
|
|
FromDtsSerializationTest(test, reportErrors);
|
|
}
|
|
|
|
catch (System.Exception ex)
|
|
{
|
|
/*throw new Exception(
|
|
string.Format(
|
|
DataPROWin7.Properties.Resources.DTS_Slice_Control_Event_ConstructionFailedString, this.GetType().FullName),
|
|
ex);*/
|
|
throw ex;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize an instance of the DTS.Slice.Control.Event class.
|
|
/// </summary>
|
|
///
|
|
/// <param name="id">
|
|
/// The <see cref="string"/> ID of this event.
|
|
/// </param>
|
|
///
|
|
/// <param name="description">
|
|
/// The <see cref="string"/> description of this event.
|
|
/// </param>
|
|
///
|
|
/// <param name="modules">
|
|
/// The list of <see cref="DTS.Slice.Control.Event.Module"/>s associated with this event.
|
|
/// </param>
|
|
///
|
|
public Event(string id, string description, List<Module> 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...
|
|
|
|
/// <summary>
|
|
/// Get a named-DAS/numbered-module accessor to this Event's modules.
|
|
/// </summary>
|
|
public DasModuleAccessor DasModules
|
|
{
|
|
get => _DasModules.Value;
|
|
private set => _DasModules.Value = value;
|
|
}
|
|
private readonly Property<DasModuleAccessor> _DasModules
|
|
= new Property<DasModuleAccessor>(
|
|
typeof(Event).Namespace + ".Event.DasModules",
|
|
new DasModuleAccessor(),
|
|
true
|
|
);
|
|
|
|
/// <summary>
|
|
/// Get a named-DAS/numbered-channel accessor to this Event's channels.
|
|
/// </summary>
|
|
public DasChannelAccessor DasChannels
|
|
{
|
|
get => _DasChannels.Value;
|
|
private set => _DasChannels.Value = value;
|
|
}
|
|
private readonly Property<DasChannelAccessor> _DasChannels
|
|
= new Property<DasChannelAccessor>(
|
|
typeof(Event).Namespace + ".Event.DasChannels",
|
|
new DasChannelAccessor(),
|
|
true
|
|
);
|
|
|
|
/// <summary>
|
|
/// Get a named-DAS/numbered-module/numbered-channel accessor to this Event's channels.
|
|
/// </summary>
|
|
public DasModuleChannelAccessor DasModuleChannels
|
|
{
|
|
get => _DasModuleChannels.Value;
|
|
private set => _DasModuleChannels.Value = value;
|
|
}
|
|
private readonly Property<DasModuleChannelAccessor> _DasModuleChannels
|
|
= new Property<DasModuleChannelAccessor>(
|
|
typeof(Event).Namespace + ".Event.DasModules",
|
|
new DasModuleChannelAccessor(),
|
|
true
|
|
);
|
|
public static bool IsG5(IDASCommunication idas)
|
|
{
|
|
return idas.SerialNumber.StartsWith("5M");
|
|
}
|
|
|
|
const string Slice6DBModule = "slice6db module";
|
|
public static bool IsSlice6DBModule(Module module)
|
|
{
|
|
if (null != module && null != module.Description && module.Description.ToLower() == Slice6DBModule)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize an instance of the DTS.Slice.Control.Event class.
|
|
/// </summary>
|
|
///
|
|
/// <param name="dases">
|
|
/// A <see cref="List"/> of <see cref="IConnectedDevice"/>s that will be used
|
|
/// to determine the dimensions of the Event's internal structures.
|
|
/// </param>
|
|
///
|
|
public Event(List<IDASCommunication> 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<Module>();
|
|
var dasTestInformations = new Dictionary<string, TestInformation>();
|
|
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 : "<NULL>" ) + ")" );
|
|
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 : "<NULL>" ) + "\"" );
|
|
var eventInfo = das.EventInfo.Events[eventIndex];
|
|
|
|
dasTestInformations.Add(das.SerialNumber, new TestInformation(eventInfo.TestID, eventInfo.Description == null ? "" : eventInfo.Description));
|
|
DasModules.Add(das.SerialNumber, new List<Module>());
|
|
DasChannels.Add(das.SerialNumber, new List<Module.Channel>());
|
|
DasModuleChannels.Add(das.SerialNumber, new ModuleChannelAccessor());
|
|
|
|
if (null != eventInfo.Modules)
|
|
{
|
|
foreach (var dasModule in new List<DASModule>(eventInfo.Modules))
|
|
{
|
|
//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.StartRecordTimestampNanoSec;
|
|
nextModule.PTPMasterSync = dasModule.PTPMasterSync;
|
|
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.Channels = new List<Module.Channel>();
|
|
|
|
var moduleType = dasModule.GetType();
|
|
if ((null != dasModule.Channels) && (dasModule.Channels.Length > 0) &&
|
|
((dasModule.Channels[0].ConfigurationMode != DASChannel.ConfigMode.DummyArm)|| IsG5(das))
|
|
)
|
|
{
|
|
foreach (var dasChannel in new List<DASChannel>(dasModule.Channels))
|
|
{
|
|
Module.Channel nextChannel;
|
|
nextModule.Channels.Add(nextChannel = Module.Channel.CreateChannel(dasChannel, nextModule, absoluteChannelNumber++));
|
|
|
|
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<short>();
|
|
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))
|
|
throw new Exception(
|
|
string.Format(
|
|
Strings.DTS_Slice_Control_Event_Event_DASTestIdMismatchString, testId, dasId, newTestId));
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the highest <see cref="int"/> absolute channel number currently in this event.
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the <see cref="double"/> per-sample threshold that when exceeded by the total basic data
|
|
/// volume of this event results in Event.IsTooLargeFor32BitVisualization to return true.
|
|
/// </summary>
|
|
///
|
|
/// <remarks>
|
|
/// 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.
|
|
/// </remarks>
|
|
///
|
|
private static readonly double MaximumVisualizationBytesPerSample = 2D;
|
|
public double TooLargeFor32BitVisualizationBytesPerSampleThreshold
|
|
{
|
|
get => _TooLargeFor32BitVisualizationBytesPerSampleThreshold.Value;
|
|
private set => _TooLargeFor32BitVisualizationBytesPerSampleThreshold.Value = value;
|
|
}
|
|
private readonly Property<double> _TooLargeFor32BitVisualizationBytesPerSampleThreshold
|
|
= new Property<double>(
|
|
typeof(Event).FullName + ".TooLargeFor32BitVisualizationBytesPerSampleThreshold",
|
|
MaximumVisualizationBytesPerSample,
|
|
true
|
|
);
|
|
|
|
/// <summary>
|
|
/// Get <see cref="bool"/> value indicating whether or not this event has more combined data than a 32 bit
|
|
/// system could handle all at once.
|
|
/// </summary>
|
|
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)
|
|
{
|
|
totalChannelDataCount += (channel.UnfilteredData as Serialization.TDAS.File.PersistentChannel).NumberOfSamples;
|
|
}
|
|
else
|
|
{
|
|
totalChannelDataCount += (channel.UnfilteredData as Serialization.SliceRaw.File.PersistentChannel).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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get <see cref="bool"/> value indicating whether or not this event contains channels with average over
|
|
/// time zero methods, but have specified an invalid averaging window.
|
|
/// </summary>
|
|
public bool ContainsChannelsActiveInvalidZeroingWindows => ChannelsWithActiveInvalidZeroingWindows.Count > 0;
|
|
|
|
/// <summary>
|
|
/// 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 ...
|
|
/// </summary>
|
|
private const short InvalidWindowAverage = short.MinValue;
|
|
/// <summary>
|
|
/// Get the list of all <see cref="DTS.Slice.Control.Event.Module.Channel"/>s that with average over time
|
|
/// zero method set, but have specified an invalid averaging window.
|
|
/// </summary>
|
|
public List<Module.Channel> ChannelsWithActiveInvalidZeroingWindows
|
|
{
|
|
get
|
|
{
|
|
try
|
|
{
|
|
var invalidZeroWindowChannels = new List<Module.Channel>();
|
|
foreach (var module in Modules)
|
|
foreach (var channel in module.Channels)
|
|
if (channel is Module.AnalogInputChannel)
|
|
{
|
|
var analogChannel = channel as Module.AnalogInputChannel;
|
|
if (Common.DAS.Concepts.Test.Module.Channel.Sensor.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) ? (double)analogChannel.ParentModule.TriggerSampleNumbers[0] : 0) + (analogChannel.ZeroAverageWindow.Begin * (double)analogChannel.ParentModule.SampleRateHz);
|
|
var windowEnd = ((analogChannel.ParentModule.TriggerSampleNumbers.Count > 0) ? (double)analogChannel.ParentModule.TriggerSampleNumbers[0] : 0) + (analogChannel.ZeroAverageWindow.End * (double)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));
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Convert this object to a DTS.Serialization.Test.
|
|
/// </summary>
|
|
///
|
|
/// <returns>
|
|
/// A <see cref="DTS.Serialization.Test"/> equivalent to this object.
|
|
/// </returns>
|
|
///
|
|
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.Guid = Guid;
|
|
that.FaultFlags = FaultFlags;
|
|
that.Modules = new List<Test.Module>();
|
|
|
|
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)) { 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));
|
|
}
|
|
return that;
|
|
}
|
|
|
|
catch (System.Exception ex)
|
|
{
|
|
throw new Exception("encountered problem converting " + GetType().FullName + " to " + typeof(Test).FullName, ex);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize this object from a DTS.Serialization.Test.
|
|
/// </summary>
|
|
///
|
|
/// <param name="that">
|
|
/// A <see cref="DTS.Serialization.Test"/> from which to initialize this object.
|
|
/// </param>
|
|
///
|
|
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;
|
|
FaultFlags = that.FaultFlags;
|
|
Guid = that.Guid;
|
|
InceptionDate = that.InceptionDate;
|
|
|
|
Modules = new List<Module>();
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Method to convert a DTS.Slice.Control.Event object to an equivalent DTS.Serialization.Test object.
|
|
/// </summary>
|
|
///
|
|
/// <param name="sliceControlEvent">
|
|
/// The <see cref="DTS.Slice.Control.Event"/> to be converted.
|
|
/// </param>
|
|
///
|
|
/// <returns>
|
|
/// A <see cref="DTS.Serialization.Test"/> that is equivalent to the specified Slice Control event.
|
|
/// </returns>
|
|
///
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// this really belongs in the channel object, but for now just abstract the function out of
|
|
/// where the logic is needed
|
|
/// </summary>
|
|
/// <param name="channel"></param>
|
|
/// <returns></returns>
|
|
private bool IsDummyChannel(Module.Channel channel)
|
|
{
|
|
if (null != channel && channel.ChannelDescriptionString.ToLower() == "dummy arm channel")
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set the base serialization directory path <see cref="string"/> for events.
|
|
/// </summary>
|
|
public static string BaseSerializationDirectory
|
|
{
|
|
get => _BaseSerializationDirectory.Value;
|
|
set => _BaseSerializationDirectory.Value = value;
|
|
}
|
|
private static readonly Property<string> _BaseSerializationDirectory
|
|
= new Property<string>(
|
|
typeof(Event).Namespace + ".BaseSerializationDirectory",
|
|
null,
|
|
false
|
|
);
|
|
|
|
/// <summary>
|
|
/// Construct the serialization path for the specified event ID.
|
|
/// </summary>
|
|
///
|
|
/// <param name="eventId">
|
|
/// The <see cref="string"/> ID of the event whose serialization path is sought.
|
|
/// </param>
|
|
///
|
|
/// <returns>
|
|
/// The <see cref="string"/> path for the specified event's serialization.
|
|
/// </returns>
|
|
///
|
|
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 + "\"" : "<NULL>"), ex);
|
|
throw new Exception("encountered problem getting target directory for test " + (null != eventId ? "\"" + eventId + "\"" : "<NULL>"), ex);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Test the specified object for equality with this object.
|
|
/// </summary>
|
|
///
|
|
/// <param name="obj">
|
|
/// The <see cref="object"/> to be tested for equality.
|
|
/// </param>
|
|
///
|
|
/// <returns>
|
|
/// <see cref="bool"/> true if the specified object has memberwise equality with
|
|
/// this object; false otherwise.
|
|
/// </returns>
|
|
///
|
|
public override bool Equals(object obj)
|
|
{
|
|
try
|
|
{
|
|
var that = obj as Event;
|
|
return null != that
|
|
&& Id.Equals(that.Id)
|
|
&& Description.Equals(that.Description)
|
|
&& Guid.Equals(that.Guid)
|
|
&& ModulesEquals(that.Modules)
|
|
&& FaultFlags.Equals(that.FaultFlags);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Test the specified object's module list for equality with this object's
|
|
/// module list.
|
|
/// </summary>
|
|
///
|
|
/// <param name="thoseModules">
|
|
/// The <see cref="List"/> of <see cref="DTS.Slice.Control.Event.Module"/> objects to be
|
|
/// compared for equality with this test's equivalent.
|
|
/// </param>
|
|
///
|
|
/// <returns>
|
|
/// <see cref="bool"/> true if the two lists contain equivalent-valued members;
|
|
/// false otherwise.
|
|
/// </returns>
|
|
///
|
|
private bool ModulesEquals(List<Module> 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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return the hash code for this object.
|
|
/// </summary>
|
|
///
|
|
/// <returns>
|
|
/// The <see cref="int"/> hash code for this object.
|
|
/// </returns>
|
|
///
|
|
public override int GetHashCode()
|
|
{
|
|
return base.GetHashCode();
|
|
}
|
|
}
|
|
}
|