This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,285 @@
using System.Collections.Generic;
using DTS.Common.Enums;
using DTS.Common.Enums.DASFactory;
using DTS.Common.SharedResource.Strings;
namespace DTS.Common
{
public static class Constants
{
public const int GETARMSTATUS_TIMEOUT = 30000;
public static readonly string[] ACCELERATION_UNITS = new[] { "g", "msec", "m/sec", "m/sec^2", "m/s^2" };
public const string ROI_TAG = "ROI";
public const string ALL_TAG = "ALL";
public const string DAS_TEST_SETUPS = "DASTestSetup";
public const int MINIMUM_VOLTAGE_INSERTION_RANGE_MV_SLICE = 10;
/// <summary>
/// Senstivity change tolerance percent default value
/// </summary>
public const double SENSITIVITY_CHANGE_TOLERANCE_PERCENT_DEFAULT = 5D;
/// <summary>
/// The max zoom to apply to a graph if the data in the graph does not meet the zoom ranges. This is specified as % full scale
/// (of capacity)
/// so for 2400 EU if the graph is a flat line the max over or under of the plot would be 24 units.
/// http://manuscript.dts.local/f/cases/29416/Limit-view-of-TSR-AIR-data-to-2-of-full-scale-in-auto-range-mode
/// these variables already existed, I just abstracted them to a common spot from two disparate spots
/// </summary>
public const double GRAPH_MIN_AUTOZOOM = 0.01D;
/// <summary>
/// The max zoom to apply to a graph. This is specified as % full scale (of signal)
/// http://manuscript.dts.local/f/cases/29416/Limit-view-of-TSR-AIR-data-to-2-of-full-scale-in-auto-range-mode
/// these variables already existed, I just abstracted them to a common spot from two disparate spots
/// </summary>
public const double GRAPH_MAX_AUTOZOOM = 1.2D;
/// <summary>
/// whether to check status line while doing realtime polling
/// http://manuscript.dts.local/f/cases/27067/
/// </summary>
public static bool CheckStatusLinesInRealtime { get; set; } = true;
/// <summary>
/// sleep time between chart updates
/// http://manuscript.dts.local/f/cases/27067/
/// </summary>
public static int UpdateIntervalRealtimeCharts { get; set; } = 100;
public const string USB = "USB";
public const string BACKUP_HEADER_EXTENSION = ".header.bak";
public const string BACKUP_FILE_EXTENSION = ".bak";
public const string DAS_CONFIGS = "DASConfigs";
public const double UNUSED_START_TIME = 0;
public const int UNUSED_DATA_COLLECTION_LENGTH = 0;
public const int MAX_USER_CHANNEL_NAME_LENGTH = 100;
public const string REPORT_DIR_NAME = "Reports";
public const string REPORT_TEMPLATE_DIR_NAME = "ReportTemplates";
public const string TEMP_FILE_EXTENSION = ".tmp";
public const string UDP_STREAM_CH10_TF2 = "2HDR";
public const string EventNumber = "_Event Number";
public const string CHANNEL_FILE_EXTENSION = ".chn";
public const string BINARY_FILE_EXTENSION = ".bin";
public const string BINARY = "Binary";
public const string ALL = "ALL";
public const string CURRENT_SUFFIX = "_CU";
public const string MESSAGEBOXBUTTON_OK = "MessageBoxButton_OK";
/// <summary>
/// This is the string _ROI_PERIOD - I'm using it when calculating extra space that might be needed
/// for downloading when you have multiple ROI
/// </summary>
public const string ROI_PERIOD = "_ROI Period";
public const string UseMeasuredExcitation = "UseMeasuredExcitation";
public const int TRACK_ANALOG_DIAGNOSTICS_DB_VERSION = 98;
// http://manuscript.dts.local/f/cases/39470/Add-UI-for-configurable-option-to-allow-UDP-aligning-to-PPS
public const int ALIGNUDPTOPPS_DB_VERSION = 98;
public const string TrackAnalogDiagnostics = "TrackAnalogDiagnostics";
public const string SensorAssembly = "SensorAssembly";
public const string ManualsFolder = "Manuals";
public const string WindowsExplorer = "explorer.exe";
//FB 23926 Moved to constants
public const string NoValue = "NOVALUE";
public const string ISO_CH_ONLY_PREFIX = "__ISO_CH_ONLY__";
//FB 25526 Moved from SLICE6AIR so they can be used by multiple classes
public const uint XML_HEADER_LENGTH = 8;
public readonly static byte[] XML_STORE_MAGIC_BYTES = new byte[] { 0xAA, 0x55, 0xA5, 0x5A };
public const ushort FILE_STORE_DSP_FILTER_ID = 104;
public const byte DEVICE_STREAMING_ONLY = 1;
/// <summary>
///FB 28107 Maximum value allowed for TDAS Tom Digital out duration
/// </summary>
public const double TDAS_TOM_DIGITAL_OUT_DURATION_MAX = 1600;
/// <summary>
/// bps = (32bit + 6x16bit) * sampling rate. Our PCM data payload is 128bit per minor frame
/// </summary>
public const int BITS_PER_MINOR_FRAME_S6A = 128;
//bps = (32 + 18*16)*sampling rate for TSR AIR - per EF
//[2:14 PM] Eric Fizer should be 18 * 16bit +32bit frame sync, no?
public const int BITS_PER_MINOR_FRAME_TSRAIR = 320;
/// <summary>
/// FB15339 DACs are 16-bit, so midpoint ADC value would be 2^15 - 1
/// </summary>
public const int ADC_MIDPOINT = 32767;
/// <summary>
/// timeout supplied to ping_ICMP
/// 14735 Updates for GM Process flow, time improvement and bug fix
/// max time in MS to wait for an individual ping attempt
/// </summary>
public static int PING_ICMP_TIMEOUT { get; set; } = 500;
/// <summary>
/// 14966 AAF Realtime rate if we're turning off AAFRealtime via the config file
/// </summary>
public const float SLICE2_NO_AAF_REALTIME_RATE = 100000F;
/// <summary>
/// FB15313 Configure S6A udp streaming
/// </summary>
public const int UDP_STREAMPROFILES_MAX = 15;
/// <summary>
/// FB15323 Restrict Sample Rates when in UART recording modes
/// </summary>
public const int UART_MODE_MAX_SAMPLERATE = 30000;
/// <summary>
/// FB30273 Implement 'Warning' Validation for Streaming sample rate greater than 10k when Digital Filtering is configured
/// </summary>
public const int SLICE6AIR_STREAMING_DIGITAL_FILTERING_MAX_SAMPLERATE = 10000;
public const int SLICE6AIR_STREAMING_DIGITAL_FILTERING_MAX_SAMPLERATE_20k = 20000;
public const int SLICE6AIR_20K_DIGITAL_FILTER_MIN_PROTOCOL = 46;
/// <summary>
/// max sample rate that digital filtering will reliably work for S6A F/W version 46 and beyond
/// http://manuscript.dts.local/f/cases/39106/Datapro-shouldnt-be-warning-about-digital-filter-availability-until-20k-sps
/// </summary>
public const decimal NANOS_PER_SECOND = 1000000000m;
public const double TEN_MILLIS_IN_SEC = 0.01D;
/// <summary>
/// Wait timeout for 3rd party executables
/// </summary>
public const int EXECUTABLE_TIMEOUT = 30000;
/// <summary>
/// FB15154 Restrict Clock Master & Clock Slave Test Setup Default profile selections
/// </summary>
public static readonly ClockSyncProfile[] MasterProfiles = { ClockSyncProfile.None,
ClockSyncProfile.Manual,
ClockSyncProfile.Master_E2E,
ClockSyncProfile.Master_E2E_PPS_OUT,
ClockSyncProfile.Master_E2E_IRIG,
ClockSyncProfile.IRIG_Master_E2E_PPS_OUT,
ClockSyncProfile.IRIG_PPS_OUT,
ClockSyncProfile.Master_E2E_IRIG_EXT_PPS,
ClockSyncProfile.Master_E2E_GPS_EXT_PPS,
ClockSyncProfile.Master_E2E_EXT_PPS,
ClockSyncProfile.IRIG,
ClockSyncProfile.IRIG_EXT_PPS,
ClockSyncProfile.GPS_EXT_PPS,
ClockSyncProfile.EXT_PPS,
//Combinations that are possible in UI, but no device supports
//30487: GPS only clock sync option should be removed
// also clean up available selections in TSD
/*ClockSyncProfile.PPS_OUT,
ClockSyncProfile.GPS,
ClockSyncProfile.GPS_PPS_OUT,
ClockSyncProfile.GPS_Master_E2E_PPS_OUT,
ClockSyncProfile.GPS_EXT_PPS_PPS_OUT,
ClockSyncProfile.GPS_EXT_PPS_Master_E2E_PPS_OUT,
ClockSyncProfile.EXT_PPS_PPS_OUT,
ClockSyncProfile.EXT_PPS_Master_E2E_PPS_OUT,
ClockSyncProfile.IRIG_EXT_PPS_PPS_OUT,
ClockSyncProfile.IRIG_EXT_PPS_Master_E2E_PPS_OUT,*/
};
public static readonly ClockSyncProfile[] SlaveProfiles = { ClockSyncProfile.None,
ClockSyncProfile.Manual,
ClockSyncProfile.Slave_E2E,
ClockSyncProfile.Slave_E2E_PPS_OUT,
//Combinations that are possible in UI, but no device supports
//30487: also clean up available selections in TSD
/*ClockSyncProfile.Auto_E2E,
ClockSyncProfile.Slave_E2E_Master_E2E_OUT,
ClockSyncProfile.Slave_E2E_Master_E2E_PPS_OUT,*/
};
public static readonly ClockSyncProfile[] OnePPSOutProfiles = { ClockSyncProfile.Slave_E2E_PPS_OUT,
ClockSyncProfile.Master_E2E_PPS_OUT,
ClockSyncProfile.IRIG_Master_E2E_PPS_OUT,
ClockSyncProfile.IRIG_PPS_OUT,
//Combinations that are possible in UI, but no device supports
ClockSyncProfile.PPS_OUT,
ClockSyncProfile.GPS_PPS_OUT,
ClockSyncProfile.GPS_Master_E2E_PPS_OUT,
ClockSyncProfile.GPS_EXT_PPS_PPS_OUT,
ClockSyncProfile.GPS_EXT_PPS_Master_E2E_PPS_OUT,
ClockSyncProfile.EXT_PPS_PPS_OUT,
ClockSyncProfile.EXT_PPS_Master_E2E_PPS_OUT,
ClockSyncProfile.IRIG_EXT_PPS_PPS_OUT,
ClockSyncProfile.IRIG_EXT_PPS_Master_E2E_PPS_OUT,
ClockSyncProfile.Slave_E2E_Master_E2E_PPS_OUT,
};
/// <summary>
/// FB15520 Restrict Recording Mode Test Setup Default selections to non-streaming
/// FB39190 Also restrict multiple-event variants of regular modes
/// FB39189 Add scheduled
/// </summary>
public static readonly RecordingModes[] NonStreamingRecordingModes = { RecordingModes.CircularBuffer, RecordingModes.CircularBufferPlusUART, RecordingModes.CircularBufferAndStreamSubSample,
RecordingModes.Recorder, RecordingModes.RecorderPlusUART, RecordingModes.RecorderAndStreamSubSample,
RecordingModes.HybridRecorder, RecordingModes.HybridAndStream, RecordingModes.ContinuousRecorder, RecordingModes.ContinuousRecorderPlusUART,
RecordingModes.RAMActive, RecordingModes.RecordOnBoot, RecordingModes.RecordOnBootPlusUART,
RecordingModes.Active, RecordingModes.Scheduled
};
/// <summary>
/// 17650 sanitize name output for certain exports
/// </summary>
public static readonly Dictionary<string, string> ExportNameFilters = new Dictionary<string, string> { { "(Voltage)", "Voltage" }, { "(Current)", "Current" } };
public const string DUMMY_MOD_DESCRIP_S6DB = "slice6db module";
public const string DUMMY_MOD_DESCRIP_POWERPRO = "powerpro module";
public const uint MaxAAFilterRateHz = 200000;
public const int PSD_DEFAULT_MAX_POW10 = 0;
public const int PSD_DEFAULT_MIN_POW10 = -12;
public const string ISOTestInfo = "_";
/// <summary>
/// 18361 NMEA data exports
/// 28173 NMEA additional data
/// </summary>
public const string NMEA_GPRMC_HEADER = "$GPRMC";
public const int NMEA_GPRMC_TIME_POSN = 1;
public const int NMEA_GPRMC_VALID_POSN = 2;
public const int NMEA_GPRMC_LAT_POSN = 3;
public const int NMEA_GPRMC_LAT_LEN = 9;
public const int NMEA_GPRMC_LATD_POSN = 4;
public const int NMEA_GPRMC_LONG_POSN = 5;
public const int NMEA_GPRMC_LONG_LEN = 10;
public const int NMEA_GPRMC_LONGD_POSN = 6;
public const int NMEA_GPRMC_VELO_POSN = 7;
public const int NMEA_GPRMC_DIR_POSN = 8;
public const int NMEA_GPRMC_DATE_POSN = 9;
public const string NMEA_GPGGA_HEADER = "$GPGGA";
public const int NMEA_GPGGA_TIME_POSN = 1;
public const int NMEA_GPGGA_VALID_POSN = 6;
public const int NMEA_GPGGA_ALT_POSN = 9;
public const int NMEA_GPGGA_ALTU_POSN = 10;
public const int ROITables_DB_VERSION = 92;
public const int EnableRepeat_DB_VERSION = 92;
public const int IgnoreShorted_DB_VERSION = 92;
public const int ONEPPS_OUT_DB_VERSION = 92;
public const int UNIX_EPOCH_TIME = 93;
//http://manuscript.dts.local/f/cases/29987/Add-CG-DP-TMATS-interval-UI-support
public const int TMATS_INTERVAL_VERSION = 93;
//FB 29978 Allowed directory & file name in Windows
public const int ALLOWED_DOWNLOAD_FILE_LENGTH = 260;
public const int ALLOWED_DOWNLOAD_DIRECTORY_LENGTH = 248;
public const int ADC_TO_UART_DB_VERSION = 93;
public const int SLICE6AIR_BR_DB_VERSION = 95;
public const int PTP_DOMAIN_ID_DB_VERSION = 95;
public const int BULK_GROUPCHANNELSETTINGS_GET_DB_VERSION = 95;
// 35514 Multiple-event UART support
public const int MULTIPLE_EVENT_UART_DB_VERSION = 96;
public const int RECORD_ON_BOOT_VERSION = 96;
public const int TSRAIR_GO_VERSION = 97;
public const int ROIPERIODCHANNELS_CHANNELID_DB_VERSION = 98;
public const int SENSOR_ASSEMBLY_DB_VERSION = 98;
public const int ALLOW_INSPECT_BEFORE_USE_DB_VERSION = 98;
public const int SLICE_TC_DB_VERSION = 99;
public const int SLICE_PRO_CAN_FD_DB_VERSION = 100;
/// <summary>
/// 38048 maximum points for a Viewer graph
/// </summary>
public const int MAX_VIEWER_POINTS = 45000000;
public const double LOWEST_NONZERO_TSR_AIR_PRETRIGGER_SECONDS = 0.0128D;
private static string scheduleStartTimeError = string.Format(StringResources.EditTestSetupPage_ScheduleMustBeInFuture, DFConstantsAndEnums.SCHEDULE_AHEAD_IN_MINUTES);
public static string ScheduleStartTimeError
{
get => scheduleStartTimeError;
}
private static string intervalError = string.Format(StringResources.EditTestSetupPage_EventLengthTooLong, DFConstantsAndEnums.TIME_TO_REARM_SECONDS);
public static string IntervalError
{
get => intervalError;
}
//FB 44523 Define the min & max font size for Top-Level navigation Tabs and Page Buttons
public const int TabAndPageButtonsFontSizeMin = 12;
public const int TabAndPageButtonsFontSizeMax = 32;
}
}

View File

@@ -0,0 +1,10 @@
namespace DTS.Common.Interface.TestSetups
{
/// <summary>
/// This interface allows DAS to be ordered within a test setup.
/// </summary>
public interface ITestDASOrder
{
int DASIndex { get; set; }
}
}

View File

@@ -0,0 +1,115 @@
using DTS.Common.Interface.Sensors.AnalogDiagnostics;
using System;
using System.ComponentModel;
using System.Data.SqlClient;
namespace DTS.Common.Classes.Sensors.AnalogDiagnostics
{
public class DiagnosticEntry : IDiagnosticEntry
{
private long? _Id = null;
public long? Id { get => _Id; set => _Id = value; }
private long _DiagnosticRunId = -1;
public long DiagnosticRunId { get => _DiagnosticRunId; set => _DiagnosticRunId = value; }
private double? _Excitation = null;
public double? Excitation { get => _Excitation; set => _Excitation = value; }
private DiagnosticStatus _ExcitationStatus = DiagnosticStatus.Untested;
public DiagnosticStatus ExcitationStatus { get => _ExcitationStatus; set => _ExcitationStatus = value; }
private double? _Offset = null;
public double? Offset { get => _Offset; set => _Offset = value; }
private DiagnosticStatus _OffsetStatus = DiagnosticStatus.Untested;
public DiagnosticStatus OffsetStatus { get => _OffsetStatus; set => _OffsetStatus = value; }
private double? _ActualRange = null;
public double? ActualRange { get => _ActualRange; set => _ActualRange = value; }
private DiagnosticStatus _ActualRangeStatus = DiagnosticStatus.Untested;
public DiagnosticStatus ActualRangeStatus { get => _ActualRangeStatus; set => _ActualRangeStatus = value; }
private double? _Noise = null;
public double? Noise { get => _Noise; set => _Noise = value; }
private DiagnosticStatus _NoiseStatus = DiagnosticStatus.Untested;
public DiagnosticStatus NoiseStatus { get => _NoiseStatus; set => _NoiseStatus = value; }
private double? _Shunt = null;
public double? Shunt { get => _Shunt; set => _Shunt = value; }
private DiagnosticStatus _ShuntStatus = DiagnosticStatus.Untested;
public DiagnosticStatus ShuntStatus { get => _ShuntStatus; set => _ShuntStatus = value; }
private int? _SensorId;
public int? SensorId { get => _SensorId; set => _SensorId = value; }
private string _SensorSerialNumber = string.Empty;
public string SensorSerialNumber { get => _SensorSerialNumber; set => _SensorSerialNumber = value; }
private int? _DASId = null;
public int? DASId { get => _DASId; set => _DASId = value; }
private string _dasSerialNumber = string.Empty;
public string DASSerialNumber { get => _dasSerialNumber; set => _dasSerialNumber = value; }
private int _dasChannelIdx = 0;
public int DASChannelIdx { get => _dasChannelIdx; set => _dasChannelIdx = value; }
private string _UserCode = string.Empty;
public string UserCode { get => _UserCode; set => _UserCode = value; }
private string _UserChannelName = string.Empty;
public string UserChannelName { get => _UserChannelName; set => _UserChannelName = value; }
private string _IsoCode = string.Empty;
public string IsoCode { get => _IsoCode; set => _IsoCode = value; }
private string _IsoChannelName = string.Empty;
public string IsoChannelName { get => _IsoChannelName; set => _IsoChannelName = value; }
private double _scaleFactor = 1;
public double ScaleFactor { get => _scaleFactor; set => _scaleFactor = value; }
private int _calibrationRecordId = -1;
public int CalibrationRecordId { get => _calibrationRecordId; set => _calibrationRecordId = value; }
private string _calibrationRecordXML = string.Empty;
public string CalibrationRecordXML { get => _calibrationRecordXML; set => _calibrationRecordXML = value; }
private DateTime _timeStamp = DateTime.MinValue;
public DateTime Timestamp { get => _timeStamp; set => _timeStamp = value; }
public DiagnosticEntry() { }
public DiagnosticEntry (SqlDataReader reader)
{
if (!DBNull.Value.Equals(reader["Id"])) { Id = (long)reader["Id"]; }
if (!DBNull.Value.Equals(reader["DiagnosticRunId"])) { DiagnosticRunId = (long)reader["DiagnosticRunId"]; }
if (!DBNull.Value.Equals(reader["Excitation"])) { Excitation = (double)reader["Excitation"]; }
if (!DBNull.Value.Equals(reader["ExcitationStatus"])) { ExcitationStatus = (DiagnosticStatus)(short)reader["ExcitationStatus"]; }
if (!DBNull.Value.Equals(reader["Offset"])) { Offset = (double)reader["Offset"]; }
if (!DBNull.Value.Equals(reader["OffsetStatus"])) { OffsetStatus = (DiagnosticStatus)(short)reader["OffsetStatus"]; }
if (!DBNull.Value.Equals(reader["ActualRange"])) { ActualRange = (double)reader["ActualRange"]; }
if (!DBNull.Value.Equals(reader["ActualRangeStatus"])) { ActualRangeStatus = (DiagnosticStatus)(short)reader["ActualRangeStatus"]; }
if (!DBNull.Value.Equals(reader["Noise"])) { Noise = (double)reader["Noise"]; }
if (!DBNull.Value.Equals(reader["NoiseStatus"])) { NoiseStatus = (DiagnosticStatus)(short)reader["NoiseStatus"]; }
if (!DBNull.Value.Equals(reader["Shunt"])) { Shunt = (double)reader["Shunt"]; }
if (!DBNull.Value.Equals(reader["ShuntStatus"])) { ShuntStatus = (DiagnosticStatus)(short)reader["ShuntStatus"]; }
if (!DBNull.Value.Equals(reader["SensorId"])) { SensorId = (int)reader["SensorId"]; }
if (!DBNull.Value.Equals(reader["SensorSerialNumber"])) { SensorSerialNumber = (string)reader["SensorSerialNumber"]; }
if (!DBNull.Value.Equals(reader["DASId"])) { DASId = (int)reader["DASId"]; }
if (!DBNull.Value.Equals(reader["DASSerialNumber"])) { DASSerialNumber = (string)reader["DASSerialNumber"]; }
if (!DBNull.Value.Equals(reader["DASChannelIdx"])) { DASChannelIdx = (short)reader["DASChannelIdx"]; }
if (!DBNull.Value.Equals(reader["UserCode"])) { UserCode = (string)reader["UserCode"]; }
if (!DBNull.Value.Equals(reader["UserChannelName"])) { UserChannelName = (string)reader["UserChannelName"]; }
if (!DBNull.Value.Equals(reader["IsoCode"])) { IsoCode = (string)reader["IsoCode"]; }
if (!DBNull.Value.Equals(reader["IsoChannelName"])) { IsoChannelName = (string)reader["IsoChannelName"]; }
if (!DBNull.Value.Equals(reader["ScaleFactor"])) { ScaleFactor = (double)reader["ScaleFactor"]; }
if (!DBNull.Value.Equals(reader["CalibrationRecordId"])) { CalibrationRecordId = (int)reader["CalibrationRecordId"]; }
if (!DBNull.Value.Equals(reader["CalibrationRecordXML"])) { CalibrationRecordXML = (string)reader["CalibrationRecordXML"]; }
if (!DBNull.Value.Equals(reader["Timestamp"])) { Timestamp = (DateTime)reader["Timestamp"]; }
}
}
}

View File

@@ -0,0 +1,634 @@
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.ComponentModel;
using System.Globalization;
using DTS.Common.Enums.Sensors;
using DTS.Common.Interface.Sensors.SoftwareFilters;
using DTS.Common.Interface.Sensors;
using System.Linq;
namespace DTS.Common.Classes.Sensors
{
[ReadOnly(true)]
public class FilterClass : INotifyPropertyChanged, IFilterClass
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, String propertyName = null)
{
if (Equals(storage, value)) return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
[ReadOnly(true)]
public FilterClassType FClass { get; set; }
//FB 13120 used for filter options drop down localization
public string FilterName
{
get
{
string name = "";
if (FClass == FilterClassType.None)
{
name = Strings.Strings.FilterClassType_None;
}
else if (FClass == FilterClassType.Unfiltered)
{
name = Strings.Strings.FilterClassType_Unfiltered;
}
else if (FClass == FilterClassType.AdHoc)
{
name = Frequency.ToString();
}
else
{
name = Frequency + " (" + FClass.ToString() + ")";
}
return name;
}
}
/// <summary>
/// Gets the numeric filter class value for the filter class; EX CFC60 returns 60, CFC1000 returns 1000
/// </summary>
/// <returns>integer for filter class name</returns>
public int GetFilterClassNumericValue()
{
switch (FClass)
{
case FilterClassType.CFC10:
return 10;
case FilterClassType.CFC60:
return 60;
case FilterClassType.CFC180:
return 180;
case FilterClassType.CFC600:
return 600;
case FilterClassType.None:
return 0;
case FilterClassType.Unfiltered:
return -2;
default: // adhoc and cfc1000 enter here
return 1000;
}
}
private double _Frequency;
[ReadOnly(true)]
public double Frequency
{
get { return _Frequency; }
set { _Frequency = value; }
}
#region Tags
internal const string FilterClassTag = "FilterClass";
internal const string ClassTag = "Class";
internal const string FrequencyTag = "Frequency";
#endregion
private string TableName;
public FilterClass(XElement elem, string prefix, string tblName, string id)
{
TableName = tblName;
XElement inner = null;
try
{
inner = elem.Element(mkTag(prefix));
}
catch (ArgumentNullException)
{
if (!string.IsNullOrEmpty(id))
{
throw new System.Exception(string.Format("{0}: Can't find tag {1} for entry {2}", TableName, prefix + "-" + FilterClassTag, id));
}
throw new System.Exception(string.Format("{0}: Can't find tag {1} in file", TableName, prefix + "-" + FilterClassTag));
}
FClass = (FilterClassType)Enum.Parse(typeof(FilterClassType), inner.Attribute(ClassTag).Value);
switch (FClass)
{
case FilterClassType.None:
_Frequency = (double)FilterClassType.None;
break;
case FilterClassType.Unfiltered:
_Frequency = (double)FilterClassType.Unfiltered;
break;
case FilterClassType.CFC10:
_Frequency = (double)FilterClassType.CFC10;
break;
case FilterClassType.CFC60:
_Frequency = (double)FilterClassType.CFC60;
break;
case FilterClassType.CFC180:
_Frequency = (double)FilterClassType.CFC180;
break;
case FilterClassType.CFC600:
_Frequency = (double)FilterClassType.CFC600;
break;
case FilterClassType.CFC1000:
_Frequency = (double)FilterClassType.CFC1000;
break;
case FilterClassType.AdHoc:
if (!double.TryParse(inner.Value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out _Frequency))
{
throw new System.Exception(string.Format("{0}: Invalid filter frequency {1}", TableName, inner.Value));
}
break;
}
}
public FilterClass(FilterClassType fc, double freq)
{
FClass = fc;
Frequency = freq;
}
public static FilterClassType GetFilterClassTypeFromNumericFC(int fc)
{
switch (fc)
{
case 1000:
case -1:
return FilterClassType.CFC1000;
case 600:
return FilterClassType.CFC600;
case 180:
return FilterClassType.CFC180;
case 60:
return FilterClassType.CFC60;
case 10:
return FilterClassType.CFC10;
case 0:
return FilterClassType.None;
case -2:
return FilterClassType.Unfiltered;
default:
return FilterClassType.None;
}
}
public FilterClass(double freq)
{
Frequency = freq;
if (freq == (double)FilterClassType.CFC10)
{
FClass = FilterClassType.CFC10;
}
else if (freq == (double)FilterClassType.CFC60)
{
FClass = FilterClassType.CFC60;
}
else if (freq == (double)FilterClassType.CFC180)
{
FClass = FilterClassType.CFC180;
}
else if (freq == (double)FilterClassType.CFC600)
{
FClass = FilterClassType.CFC600;
}
else if (freq == (double)FilterClassType.CFC1000)
{
FClass = FilterClassType.CFC1000;
}
else if (freq == 0)
{
FClass = FilterClassType.None;
}
else if (freq == (double)FilterClassType.Unfiltered)
{
FClass = FilterClassType.Unfiltered;
}
else
{
FClass = FilterClassType.AdHoc;
//FB 13120 set the frequency for ad hoc filters
Frequency = freq;
}
}
/// <summary>
///FB 13120 Specify and return the default filter class
/// </summary>
/// <returns></returns>
public static FilterClass GetDefaultFilterClass(List<ISoftwareFilter> softwareFilters)
{
if (softwareFilters == null)
{
return new FilterClass(FilterClassType.CFC1000);
}
var softwareFilter = softwareFilters.Find(p => p.IsDefault);
FilterClass fc = null;
switch (softwareFilter?.ISOCode)
{
case '0':
fc = new FilterClass(FilterClassType.Unfiltered);
break;
case 'P':
fc = new FilterClass(FilterClassType.None);
break;
case 'S':
fc = new FilterClass(FilterClassType.AdHoc, softwareFilter.Frequency);
break;
case 'A':
fc = new FilterClass(FilterClassType.CFC1000);
break;
case 'B':
fc = new FilterClass(FilterClassType.CFC600);
break;
case 'C':
fc = new FilterClass(FilterClassType.CFC180);
break;
case 'D':
fc = new FilterClass(FilterClassType.CFC60);
break;
default:
fc = new FilterClass(FilterClassType.CFC1000);
break;
}
return fc;
}
/// <summary>
/// FB 13120 Get the filter class based on the isoCode provided
/// </summary>
/// <param name="isoCode"></param>
/// <param name="frequency">this frequency will be used for AdHoc filter</param>
/// <returns></returns>
public static FilterClass GetFilterClassFromIsoCode(string isoCode, double frequency = 0)
{
if (string.IsNullOrEmpty(isoCode))
{
return new FilterClass(FilterClassType.CFC1000);
}
FilterClass fc = null;
switch (isoCode.ToUpper())
{
case "0":
fc = new FilterClass(FilterClassType.Unfiltered);
break;
case "P":
fc = new FilterClass(FilterClassType.None);
break;
case "S":
fc = new FilterClass(FilterClassType.AdHoc, frequency);
break;
case "A":
fc = new FilterClass(FilterClassType.CFC1000);
break;
case "B":
fc = new FilterClass(FilterClassType.CFC600);
break;
case "C":
fc = new FilterClass(FilterClassType.CFC180);
break;
case "D":
fc = new FilterClass(FilterClassType.CFC60);
break;
default:
fc = new FilterClass(FilterClassType.CFC1000);
break;
}
return fc;
}
/// <summary>
/// FB 15574 Get the FilterClass setting from cfc iso code
/// </summary>
/// <param name="cfcIsoCode">cfc iso code ex: A</param>
/// <returns>filter class setting on format of FilterType,Frequency ex: None,0 </returns>
public static string GetFilterClassSettingFromCFC(string cfcIsoCode)
{
var filterClass = GetFilterClassFromIsoCode(cfcIsoCode);
return $"{filterClass.FClass.ToString()},{filterClass.Frequency}";
}
/// <summary>
///FB 15574 Get the FilterClass setting from FilterClass
/// </summary>
/// <param name="filterClass"></param>
/// <returns>filter class setting on format of FilterType,Frequency ex: None,0 </returns>
public static string GetFilterClassSettingFromFilterClass(IFilterClass filterClass)
{
return $"{filterClass.FClass.ToString()},{filterClass.Frequency}";
}
public static double GetFrequencyFromFilterClassType(FilterClassType filterClassType)
{
if (filterClassType == FilterClassType.AdHoc)
{
throw new Exception("GetFrequencyFromFilterClassType: AdHoc FilterClassType does not have frequency associated");
}
return (double)filterClassType;
}
public static FilterClass GetFilterClassFromFilterClassType(FilterClassType filterClassType, double adHocFrequency = 0)
{
if (filterClassType == FilterClassType.AdHoc)
{
return new FilterClass(filterClassType, adHocFrequency);
}
return new FilterClass(filterClassType);
}
public static FilterClass GetFilterClassFromFilterClassSetting(string filterClassSetting)
{
if (string.IsNullOrEmpty(filterClassSetting))
{
return GetFilterClassFromFilterClassType(FilterClassType.Unfiltered);
}
var setting = filterClassSetting.Split(',');
if (Enum.TryParse(setting[0], out FilterClassType fct))
{
return GetFilterClassFromFilterClassType(fct, Convert.ToDouble(setting[1]));
}
return GetFilterClassFromFilterClassType(FilterClassType.Unfiltered);
}
public FilterClass(FilterClassType fc)
{
FClass = fc;
switch (fc)
{
case FilterClassType.None:
Frequency = 0;
break;
case FilterClassType.AdHoc:
Frequency = (double)FilterClassType.AdHoc;
break;
case FilterClassType.Unfiltered:
Frequency = (double)FilterClassType.Unfiltered;
break;
case FilterClassType.CFC10:
Frequency = (double)FilterClassType.CFC10;
break;
case FilterClassType.CFC60:
Frequency = (double)FilterClassType.CFC60;
break;
case FilterClassType.CFC180:
Frequency = (double)FilterClassType.CFC180;
break;
case FilterClassType.CFC600:
Frequency = (double)FilterClassType.CFC600;
break;
case FilterClassType.CFC1000:
Frequency = (double)FilterClassType.CFC1000;
break;
default:
throw new System.Exception("FilterClass: unknown class");
}
}
public XElement ToXElement(string prefix)
{
var element = new XElement(mkTag(prefix), Frequency);
element.SetAttributeValue(ClassTag, FClass.ToString());
return element;
}
public void Update(XElement elem, string prefix)
{
elem.SetElementValue(mkTag(prefix), Frequency);
var element = elem.Element(mkTag(prefix));
element.SetAttributeValue(ClassTag, FClass.ToString());
}
public static string mkTag(string prefix)
{
return prefix + "-" + FilterClassTag;
}
public override string ToString()
{
switch (FClass)
{
case FilterClassType.None:
return "None";
case FilterClassType.Unfiltered:
return "Unfiltered";
case FilterClassType.CFC10:
return string.Format("{0} (CFC10)", (int)FilterClassType.CFC10);
case FilterClassType.CFC60:
return string.Format("{0} (CFC60)", (int)FilterClassType.CFC60);
case FilterClassType.CFC180:
return string.Format("{0} (CFC180)", (int)FilterClassType.CFC180);
case FilterClassType.CFC600:
return string.Format("{0} (CFC600)", (int)FilterClassType.CFC600);
case FilterClassType.CFC1000:
return string.Format("{0} (CFC1000)", (int)FilterClassType.CFC1000);
case FilterClassType.AdHoc:
return ((int)Frequency).ToString();
}
throw new System.Exception("FilterClass.ToString: Invalid class=" + FClass.ToString());
}
public FilterClass(string fclass)
{
int fc;
if (int.TryParse(fclass, NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out fc))
{
switch (fc)
{
case 17:
FClass = FilterClassType.CFC10;
_Frequency = (double)FClass;
return;
case 100:
FClass = FilterClassType.CFC60;
_Frequency = (double)FClass;
return;
case 300:
FClass = FilterClassType.CFC180;
_Frequency = (double)FClass;
return;
case 1000:
FClass = FilterClassType.CFC600;
_Frequency = (double)FClass;
return;
case 1650:
FClass = FilterClassType.CFC1000;
_Frequency = (double)FClass;
return;
}
}
if (string.IsNullOrEmpty(fclass) || fclass == "None")
{
FClass = FilterClassType.None;
}
else if (fclass.Contains("Unfiltered"))
{
FClass = FilterClassType.Unfiltered;
_Frequency = (double)FilterClassType.Unfiltered;
}
else if (fclass.Contains("CFC1000"))
{
FClass = FilterClassType.CFC1000;
_Frequency = (double)FilterClassType.CFC1000;
}
else if (fclass.Contains("CFC600"))
{
FClass = FilterClassType.CFC600;
_Frequency = (double)FilterClassType.CFC600;
}
else if (fclass.Contains("CFC60"))
{
FClass = FilterClassType.CFC60;
_Frequency = (double)FilterClassType.CFC60;
}
else if (fclass.Contains("CFC180"))
{
FClass = FilterClassType.CFC180;
_Frequency = (double)FilterClassType.CFC180;
}
else
{
//FB 13120 parse and set frequncy
double freq = 0;
if (double.TryParse(fclass, out freq))
{
FClass = FilterClassType.AdHoc;
_Frequency = freq;
}
else
{
FClass = FilterClassType.CFC1000;
_Frequency = (double)FilterClassType.CFC1000;
}
}
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (!(obj is FilterClass))
{
return false;
}
var filterObj = obj as FilterClass;
//FB 13120 needs this since the frequency would be different (-2 & 0) for unfiltered case
if (FClass == filterObj.FClass && FClass == FilterClassType.Unfiltered)
{
return true;
}
return FClass == filterObj.FClass && Frequency == filterObj.Frequency;
}
public int CompareTo(object filterClass)
{
IFilterClass fc = filterClass as FilterClass;
if (this == null)
{
if (fc == null)
{
// both null, equal
return 0;
}
// left null but not right
return -1;
}
if (fc == null)
{
// left not null, right null
return 1;
}
if (FClass != FilterClassType.None)
return fc.FClass == FilterClassType.None ? 1 : Frequency.CompareTo(fc.Frequency);
if (fc.FClass == FilterClassType.None)
{
return 0;
}
return -1;
}
/// <summary>
/// returns an identical hash index for any two "equal" filterclass objects
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
//.equals compares frequency and class, but we just need to guarantee that
//equal objects hash to the same index
return Convert.ToInt32(Frequency);
}
/// <summary>
/// FB 13120 Factory method to create a filter class
/// </summary>
/// <param name="fc"></param>
/// <param name="frequency"></param>
/// <returns></returns>
public static IFilterClass CreateFilterClass(FilterClassType fc, double frequency = 0)
{
if (fc == FilterClassType.AdHoc)
{
return new FilterClass(frequency);
}
else
{
return new FilterClass(fc);
}
}
/// <summary>
/// Get the filter class based on the string cfc
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static IFilterClass GetFilterClassFromString(string s)
{
if (string.IsNullOrEmpty(s)) return new FilterClass(FilterClassType.Unfiltered);
s = s.ToLower().Replace("cfc", "").Replace("hz", "").Trim();
double freq = 0;
if (double.TryParse(s, out freq))
{
switch (freq)
{
case 10:
return new FilterClass(FilterClassType.CFC10);
case 60:
return new FilterClass(FilterClassType.CFC60);
case 180:
return new FilterClass(FilterClassType.CFC180);
case 600:
return new FilterClass(FilterClassType.CFC600);
case 1000:
return new FilterClass(FilterClassType.CFC1000);
default:
return new FilterClass(FilterClassType.AdHoc, freq);
}
}
else
{
switch (s.ToLower())
{
case "unfiltered":
return new FilterClass(FilterClassType.Unfiltered);
case "none":
return new FilterClass(FilterClassType.None);
default:
return new FilterClass(FilterClassType.Unfiltered);
}
}
}
}
}