--- source_files: - Common/DTS.CommonCore/Classes/DTS.Viewer/TestMetadata/TestMetadata.cs - Common/DTS.CommonCore/Classes/DTS.Viewer/TestMetadata/TestGraphs.cs - Common/DTS.CommonCore/Classes/DTS.Viewer/TestMetadata/TestSetupMetadata.cs - Common/DTS.CommonCore/Classes/DTS.Viewer/TestMetadata/TestRunMetadata.cs - Common/DTS.CommonCore/Classes/DTS.Viewer/TestMetadata/TestSummary.cs - Common/DTS.CommonCore/Classes/DTS.Viewer/TestMetadata/TestModule.cs - Common/DTS.CommonCore/Classes/DTS.Viewer/TestMetadata/TestChannel.cs - Common/DTS.CommonCore/Classes/DTS.Viewer/TestMetadata/TestMetadataList.cs generated_at: "2026-04-16T02:42:52.937741+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "c38901448183a71b" --- # Documentation: TestMetadata Module ## 1. Purpose This module provides data structures and parsing logic for loading, representing, and managing test metadata from XML-based `.dts` files in the DTS Viewer system. It defines core domain models (`TestMetadata`, `TestRunMetadata`, `TestSetupMetadata`, `TestModule`, `TestChannel`, `TestGraphs`, `TestSummary`) that encapsulate test configuration, hardware setup, channel definitions, and summary information. The `TestMetadataList` class is responsible for deserializing XML metadata files into strongly-typed objects and constructing `TestSummary` instances for UI consumption, including timestamp resolution using PTP1588 timing data when available. ## 2. Public Interface ### `TestMetadataList` #### `GetTestSummaryListAsync(IBaseViewModel parent, string path, string file, string pattern = "")` - **Behavior**: Asynchronous wrapper (currently synchronous implementation) that returns an `ObservableCollection` by parsing `.dts` files in the specified directory. Uses `pattern` to filter files (default: `.dts`). Requires `parent` for view model hierarchy. #### `GetTestSummaryList(IBaseViewModel parent, string path, string file = "", string pattern = "")` - **Behavior**: Synchronously returns an `ObservableCollection` by parsing `.dts` files. Uses `parent` to set `TestSummary.Parent`. #### `GetTestSummaryList(string path, string file = "", string pattern = "")` - **Behavior**: Same as above but without a `parent` parameter (used when parent is not applicable or set later). #### `GetTestMetadataList(XDocument xDoc, string path, string file)` - **Behavior**: Parses an `XDocument` (loaded `.dts` XML) into a `List`. Handles channel array initialization and publishes errors via `IEventAggregator` on failure. Returns empty list on exception. ### `TestMetadata` - **Properties**: - `ITestRunMetadata TestRun { get; set; }` - `ITestSetupMetadata TestSetup { get; set; }` - **Behavior**: Simple container for test run and setup metadata. ### `TestRunMetadata` - **Properties**: - `string Name { get; set; }` — Logical test name (from XML `@Id` attribute). - `string Id { get; set; }` — File name without extension (derived from `@FilePath`). - `string Description { get; set; }` - `bool InlineSerializedData { get; set; }` - `string TestGuid { get; set; }` - `int FaultFlags { get; set; }` - `string Software { get; set; }` - `string SoftwareVersion { get; set; }` - `string DataType { get; set; }` - `DateTime FileDate { get; set; }` - `string FilePath { get; set; }` - `List Modules { get; set; }` - `List Channels { get; set; }` - `List CalculatedChannels { get; set; }` - `bool IsSelected { get; set; }` - **Events**: - `event PropertyChangedEventHandler PropertyChanged` — Implements `INotifyPropertyChanged`. ### `TestSetupMetadata` - **Properties**: - `string SetupName { get; set; }` - `DateTime TimeStamp { get; set; }` - `List TestGraphs { get; set; }` - `CalibrationBehaviors CalibrationBehavior { get; set; }` ### `TestGraphs` - **Properties**: - `string Name { get; set; }` - `string HardwareChannelName { get; set; }` - `List ChannelIds { get; set; }` - `List Channels { get; set; }` ### `TestModule` - **Properties**: - `string SerialNumber { get; set; }` - `string BaseSerialNumber { get; set; }` - `int AaFilterRateHz { get; set; }` - `int Number { get; set; }` - `int NumberOfSamples { get; set; }` - `int UnsubsampledNumberOfSamples { get; set; }` - `double RequestedPostTriggerSeconds { get; set; }` - `double RequestedPreTriggerSeconds { get; set; }` - `double PostTriggerSeconds { get; set; }` - `double PreTriggerSeconds { get; set; }` - `string RecordingMode { get; set; }` - `int SampleRateHz { get; set; }` - `int StartRecordSampleNumber { get; set; }` - `int NumberOfChannels { get; set; }` - `bool InlineSerializedData { get; set; }` - `int StartRecordTimestampSec { get; set; }` - `int StartRecordTimestampNanoSec { get; set; }` - `int TriggerTimestampSec { get; set; }` - `int TriggerTimestampNanoSec { get; set; }` - `List TriggerSampleNumbers { get; set; }` — *Always empty* (see *Gotchas*). - `bool PTPMasterSync { get; set; }` - `int TiltSensorAxisX/Y/ZDegreesPre/Post { get; set; }` - `int TemperatureLocation1/2/3/4Pre/Post { get; set; }` - `List Channels { get; set; }` - `List CalculatedChannels { get; set; }` - `bool IsSelected { get; set; }` - **Events**: - `event PropertyChangedEventHandler PropertyChanged` ### `TestChannel` - **Properties**: - `string Group { get; set; }` - `string SubGroup { get; set; }` - `bool IsGraphChannel { get; set; }` - `string GraphName { get; set; }` - `string TestId { get; set; }` - `string TestSetupName { get; set; }` - `string ModuleSerialNumber { get; set; }` - `string SerialNumber { get; set; }` - `string ChannelId { get; set; }` - `string ChannelDisplayName { get; set; }` - `string Description { get; set; }` - `string IsoCode { get; set; }` - `string IsoChannelName { get; set; }` - `string UserCode { get; set; }` - `string UserChannelName { get; set; }` - `string ChannelGroupName { get; set; }` - `string ChannelType { get; set; }` - `bool IsCalculatedChannel { get; set; }` - `int Number { get; set; }` - `string DigitalMultiplier { get; set; }` - `string DigitalMode { get; set; }` - `DateTime Start { get; set; }` - `string Bridge { get; set; }` - `double BridgeResistanceOhms { get; set; }` - `double ZeroPoint { get; set; }` - `string ChannelDescriptionString { get; set; }` - `string ChannelName2 { get; set; }` - `string HardwareChannelName { get; set; }` - `double DesiredRange { get; set; }` - `double ActualMaxRangeEu { get; set; }` - `double ActualMinRangeEu { get; set; }` - `double ActualMaxRangeAdc { get; set; }` — Always `short.MaxValue` - `double ActualMinRangeAdc { get; set; }` — Always `short.MinValue` - `double ActualMaxRangeMv { get; set; }` - `double ActualMinRangeMv { get; set; }` - `double Sensitivity { get; set; }` - `string SoftwareFilter { get; set; }` - `bool ProportionalToExcitation { get; set; }` - `bool IsInverted { get; set; }` - `string LinearizationFormula { get; set; }` - `bool IsSubsampled { get; set; }` - `int AbsoluteDisplayOrder { get; set; }` - `DateTime LastCalibrationDate { get; set; }` - `string SensorId { get; set; }` - `int OffsetToleranceLowMv { get; set; }` - `int OffsetToleranceHighMv { get; set; }` - `int DataFlag { get; set; }` - `string ExcitationVoltage { get; set; }` - `string Eu { get; set; }` - `bool CalSignalEnabled { get; set; }` - `bool ShuntEnabled { get; set; }` - `bool VoltageInsertionCheckEnabled { get; set; }` - `bool RemoveOffset { get; set; }` - `string ZeroMethod { get; set; }` - `double ZeroAverageWindowBegin { get; set; }` - `double ZeroAverageWindowEnd { get; set; }` - `int InitialEu { get; set; }` - `string InitialOffset { get; set; }` - `int UnsubsampledSampleRateHz { get; set; }` - `double MeasuredShuntDeflectionMv { get; set; }` - `double TargetShuntDeflectionMv { get; set; }` - `double MeasuredExcitationVoltage { get; set; }` - `double FactoryExcitationVoltage { get; set; }` - `double TimeOfFirstSample { get; set; }` - `double Multiplier { get; set; }` - `double UserOffsetEu { get; set; }` - `int UnitConversion { get; set; }` - `bool AtCapacity { get; set; }` - `int CapacityOutputIsBasedOn { get; set; }` - `string SourceChannelNumber { get; set; }` - `string SourceModuleNumber { get; set; }` - `string SourceModuleSerialNumber { get; set; }` - `string Calculation { get; set; }` - `int SampleRateHz { get; set; }` - `string SensitivityUnits { get; set; }` - `int SensorCapacity { get; set; }` - `string SensorPolarity { get; set; }` - `int ChannelNumber { get; set; }` - `string BinaryFileName { get; set; }` - `string BinaryFilePath { get; set; }` - `double Xmax { get; set; }` - `double Xmin { get; set; }` - `int SequentialNumbers { get; set; }` - `ITestSetupMetadata ParentTestSetup { get; set; }` - `ITestModule ParentModule { get; set; }` - `IBaseViewModel Parent { get; set; }` - `Color ChannelColor { get; set; }` - `string ErrorMessage { get; set; }` - `bool IsError { get; set; }` - `Color? ErrorColor { get; set; }` — Derived from `IsError`. - `bool IsLocked { get; set; }` - `bool CanLock { get; set; }` - `bool CanSelectChannel { get; set; }` - `bool IsExpanded { get; set; }` - `bool IsSelected { get; set; }` - `double MinADC/MaxADC/AveADC/StdDevADC/T0ADC { get; set; }` - `double MinMV/MaxMV/AveMV/StdDevMV/T0MV { get; set; }` - `double MinEU/MaxEU/AveEU/StdDevEU/T0EU { get; set; }` - `double MinY/MaxY/AveY/StdDevY/T0Value { get; set; }` - **Methods**: - `void SetChannelDescriptionAndDisplayName(string channelDescription)` — Sets `ChannelDescriptionString` and `ChannelDisplayName`. - `ITestChannel Copy()` — Shallow copy via `MemberwiseClone()`. - `override string ToString()` — Returns `ChannelDescriptionString` or `"N/A"` if test-specific embedded. - **Events**: - `event PropertyChangedEventHandler PropertyChanged` — Inherited from `BasePropertyChanged`. ### `TestSummary` - **Properties**: - `string Id { get; set; }` — Concatenation of `TestRun.Id` and event number from `FilePath`. - `string SetupName { get; set; }` - `string Description { get; set; }` - `int ChannelCount { get; set; }` - `DateTime FileDate { get; set; }` - `DateTime TimeStamp { get; set; }` — Derived from module PTP timestamps if valid, else `TestSetup.TimeStamp`. - `string DataType { get; set; }` - `bool IsSelected { get; set; }` - `List Graphs { get; set; }` - `List Channels { get; set; }` - `List CalculatedChannels { get; set; }` - `IBaseViewModel Parent { get; set; }` - `CalibrationBehaviors CalibrationBehavior { get; set; }` — Default: `NonLinearIfAvailable`. - `ITestMetadata TestMetadata { get; set; }` - **Commands**: - `DelegateCommand IsSelectedCommand { get; }` — Toggles selection and updates `Parent.SelectedTestSummaryList`. - **Methods**: - `void SelectionChanged()` — Adds/removes `this` from `Parent.SelectedTestSummaryList` and calls `PublishSelectedTestSummaryList()` on parent. - `void OnPropertyChanged(string propertyName)` — Raises `PropertyChanged`. - **Events**: - `event PropertyChangedEventHandler PropertyChanged` - **Constants**: - `public const string ROI_SUFFIX = @"_ROI Period";` ## 3. Invariants - **`TestMetadata`**: Must contain non-null `TestRun` and `TestSetup` references after successful parsing. - **`TestRunMetadata.Channels` and `TestRunMetadata.CalculatedChannels`**: Initialized as empty lists during parsing if missing in XML. - **`TestModule.TriggerSampleNumbers`**: Always initialized as an empty list; never populated (see *Gotchas*). - **`TestChannel.ChannelId`**: If missing or `-1` in XML, defaults to `m.GetHashCode().ToString()` (non-deterministic). - **`TestChannel.HardwareChannelName`**: For calculated channels, always set to `"N/A"` (via `Strings.Strings.Table_NA`). - **`TestChannel.SerialNumber`**: For calculated channels, always set to `"N/A"`. - **`TestSummary.TimeStamp`**: Falls back to `TestSetup.TimeStamp` if PTP timestamps are invalid or unavailable. - **`TestSummary.Id`**: Always includes event number extracted from `FilePath` via `ParseEventNumber`. - **`TestChannel.IsCalculatedChannel`**: Must be `true` for channels loaded via `LoadTestCalculatedChannels`. - **`TestSummary.IsSelected`**: Setter enforces selection logic via `SelectionChanged()` and `Parent` interaction. ## 4. Dependencies ### Internal Dependencies (from source): - **Interfaces**: - `DTS.Common.Interface.ITestMetadata`, `ITestRunMetadata`, `ITestSetupMetadata`, `ITestGraphs`, `ITestModule`, `ITestChannel`, `ITestSummary`, `IBaseViewModel`, `IGraphMainViewModel` - **Enums**: - `DTS.Common.Enums.Sensors.CalibrationBehaviors` - **Utilities**: - `DTS.Common.XMLUtils.TestMetadataXml` - `DTS.Common.Base.BasePropertyChanged` - `DTS.Common.Constants.EventNumber` - `DTS.Common.Utils.TestUtils`, `PTP1588Timestamps` - `DTS.Common.XMLUtils.TestMetadataFields`, `TestSetupMetadataFields`, `TestGraphsFields`, `TestModuleFields`, `TestChannelFields` - `DTS.Common.Strings.Strings` - **Prism Framework**: - `Microsoft.Practices.Prism.Commands.DelegateCommand` - `Microsoft.Practices.Prism.Events.IEventAggregator`, `Events.PageErrorEvent` - `Microsoft.Practices.ServiceLocation.ServiceLocator` ### External Dependencies: - `System.Xml.Linq` - `System.Collections.ObjectModel` - `System.ComponentModel` - `System.Windows.Media` (for `Color`) ### Inferred Consumers: - UI view models (`ITestSummaryListViewModel`, `IGraphMainViewModel`) that interact with `TestSummary` and `TestChannel`. - XML loading utilities (`TestMetadataXml`) for parsing `.dts` files. - Event aggregation system for error reporting. ## 5. Gotchas - **`TestModule.TriggerSampleNumbers` is always empty**: The `LoadTriggerSampleNumbers` method ignores its input and returns `new List()`. This field is likely unused or deprecated. - **Non-deterministic `ChannelId` for missing IDs**: If `ChannelId` attribute is missing or `-1`, `m.GetHashCode().ToString()` is used, which is not stable across runs or app restarts. - **Calculated channel data loss**: For calculated channels, many fields (e.g., `IsoCode`, `IsoChannelName`, `UserCode`, `UserChannelName`, `HardwareChannelName`, `SerialNumber`) are hardcoded to `"N/A"`. Some fields like `FactoryExcitationVoltage` and `TimeOfFirstSample` are incorrectly assigned values from unrelated attributes (e.g., `UnsubsampledSampleRateHz` → `FactoryExcitationVoltage`). - **`TestRunMetadata.Id` vs `Name` confusion**: `Id` is derived from file name (`Path.GetFileNameWithoutExtension(FilePath)`), while `Name` comes from XML `@Id` attribute. This may be counterintuitive. - **`TestSummary.TimeStamp` fallback behavior**: Uses `TestSetup.TimeStamp`