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,65 @@
---
source_files:
- Common/DTS.Common.Import/DatabaseLocks/LockImportGroups.cs
- Common/DTS.Common.Import/DatabaseLocks/LockImportTestSetups.cs
- Common/DTS.Common.Import/DatabaseLocks/LockImportSensors.cs
generated_at: "2026-04-17T15:39:02.672881+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "2421f56d39216d6a"
---
# Documentation: DTS.Common.Import.DatabaseLocks
## 1. Purpose
This module provides database locking mechanisms for import operations, ensuring that concurrent imports do not conflict by acquiring locks on Groups, TestSetups, and Sensors before import proceeds. It implements the `ILockImport` interface across three classes—`LockImportGroups`, `LockImportTestSetups`, and `LockImportSensors`—each managing locks for a specific entity type. The module handles lock acquisition, detection of contended locks (locks held by other users), automatic reclamation of expired "stranded" locks, and privileged lock stealing by administrators. All three classes reference FB 36740 in their namespace comments, suggesting they were created to address a specific feature request or bug fix.
---
## 2. Public Interface
### Interface: `ILockImport` (from `DTS.Common.Import.Interfaces`)
All three classes implement this interface with the following members:
#### `bool Contended { get; }`
Returns `true` if any items could not be locked because another user holds the lock.
#### `void FreeLock(ref ImportObject importObject)`
Releases all locks currently held by this instance. Iterates through the internal locked items list and calls `LockManager.FreeLock` for each. The `importObject` parameter is passed by reference but **is not used** in the implementation.
#### `void SetLock(ref ImportObject importObject, ref StringBuilder message)`
Attempts to acquire locks on all relevant items from the `importObject`. Populates the `message` StringBuilder with details of any contended items. Clears internal lock tracking lists at the start of execution.
#### `bool StealLock(bool proceed)`
Attempts to forcibly acquire contended locks. Returns `true` if no contention exists or if locks were successfully stolen; `false` if the user lacks admin privileges or `proceed` is `false`.
---
### Class: `LockImportGroups`
**Constructor:**
```csharp
public LockImportGroups(User currentUser, double strandedLockTimeoutMinutes)
```
**Behavior:**
- Locks items from `importObject.StaticGroups()`
- Uses `LockManager.ItemCategories.Group` for lock operations
- Tracks locks in `_lockedGroups` (successful) and `_contendedGroups` (failed due to contention)
- Uses `StringResources.ImportTestSetup_GroupsLocked` for contention messages
---
### Class: `LockImportTestSetups`
**Constructor:**
```csharp
public LockImportTestSetups(User currentUser, double strandedLockTimeoutMinutes)
```
**Behavior:**
- Locks items from `importObject.TestSetups()`
- Uses `LockManager.ItemCategories.TestSetup` for initial lock attempts
- Tracks locks in `_lockedTests` (

View File

@@ -0,0 +1,94 @@
---
source_files:
- Common/DTS.Common.Import/Factories/CSVTestParserFactory.cs
- Common/DTS.Common.Import/Factories/DatabaseLocksFactory.cs
- Common/DTS.Common.Import/Factories/CSVSensorParserFactory.cs
- Common/DTS.Common.Import/Factories/SaveVariantFactory.cs
- Common/DTS.Common.Import/Factories/XmlParserFactory.cs
generated_at: "2026-04-17T15:35:40.559078+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "eef1e6fa8b308008"
---
# DTS.Common.Import.Factories Documentation
## 1. Purpose
This module provides a collection of factory classes responsible for creating and configuring parsers, persisters, and database locks for the DTS import system. The factories abstract the instantiation logic for versioned CSV parsers (tests and sensors), XML parsers (with version-specific handling), save handlers for various import entity types, and database locking mechanisms. This design centralizes object creation, enabling consistent initialization and easier maintenance of the import pipeline.
---
## 2. Public Interface
### CSVTestParserFactory
**Class:** `DTS.Common.Import.Factories.CSVTestParserFactory`
| Method | Signature | Description |
|--------|-----------|-------------|
| `CreateCSVParsers` | `public static IParseCSVTest[] CreateCSVParsers()` | Creates and returns an array of CSV test parsers for versions 0, 5, and 6. Parsers are instantiated in order and returned as an array. |
---
### DatabaseLocksFactory
**Class:** `DTS.Common.Import.Factories.DatabaseLocksFactory` (static)
| Method | Signature | Description |
|--------|-----------|-------------|
| `Create` | `public static List<ILockImport> Create(ImportObject importObject, User user, double strandedLockTimeoutMinutes)` | Creates a list of lock import objects based on the contents of the provided `ImportObject`. Only creates locks for entity types that have data (TestSetups, Sensors, StaticGroups). |
---
### CSVSensorParserFactory
**Class:** `DTS.Common.Import.Factories.CSVSensorParserFactory`
| Method | Signature | Description |
|--------|-----------|-------------|
| `CreateCSVParsers` | `public static IReadOnlyDictionary<int, IParseCSVSensor> CreateCSVParsers(ICalibrationImport import, ZeroMethodOptions zmOptions, IImportNotification importNotification, bool importCreateDynamicGroups, bool useISOCodeFilterMapping, bool useZeroForUnfiltered)` | Creates a read-only dictionary mapping version numbers to CSV sensor parsers. Initializes parsers for versions 0, 2, 3, and 4 with the provided configuration parameters. |
---
### SaveVariantFactory
**Class:** `DTS.Common.Import.Factories.SaveVariantFactory` (static)
| Method | Signature | Description |
|--------|-----------|-------------|
| `CreateVariants` | `public static List<IPersistImport> CreateVariants(ImportObject importObject, ImportNotification importNotification, User user, Func<bool> isCanceled, bool showCheckoutButton)` | Creates a list of save handlers (`IPersistImport`) for all entity types present in the `ImportObject`. Handles CustomerDetails, TestEngineerDetails, LabDetails, SensorModels, Sensors, Users, GlobalSettings, Hardware, GroupTemplates, Groups, and TestSetups. Conditionally creates checkout test setups when `showCheckoutButton` is true. |
---
### XmlParserFactory
**Class:** `DTS.Common.Import.XmlParserFactory` (static)
| Property | Type | Description |
|----------|------|-------------|
| `UIItems` | `List<IUIItems>` | Static property for UI items used during XML parsing. |
| `ImportNotification` | `IImportNotification` | Static property for import notifications. |
| Method | Signature | Description |
|--------|-----------|-------------|
| `CreateXMLParsers` | `public static IEnumerable<IParseVariant> CreateXMLParsers(string fileName, IImportNotification importNotification, Func<bool> isCanceled, bool skipNormalizing)` | Entry point for creating XML parsers. Reads the file to determine import version and delegates to version-specific factory methods. |
| `LessThan20XMLVersion` | `private static List<IParseVariant> LessThan20XMLVersion(XmlElement node, double importVersion)` | Creates parsers for XML versions below 2.0. Handles CustomChannels, CustomMainLocs, DASList, Sensors, Calibrations, GroupTemplates, Groups, and TestSetups. |
| `GreaterOrEqual20XMLVersion` | `private static List<IParseVariant> GreaterOrEqual20XMLVersion(XmlElement node, double importVersion, bool skipNormalizing)` | Creates parsers for XML versions 2.0 and above. Handles LabDetails, CustomerDetails, TestEngineerDetails, DASList, Sensors, Calibrations, GroupTemplates, Groups, TestSetups, and Users. |
---
## 3. Invariants
- **CSVTestParserFactory**: Always returns parsers in the order: Version0, Version5, Version6. The array length is always 3.
- **CSVSensorParserFactory**: The returned dictionary is keyed by the parser's `Version` property (accessed via `v0.Version`, `v2.Version`, etc.). Versions 0, 2, 3, and 4 are always included.
- **DatabaseLocksFactory**: Only creates lock objects for entity types where `importObject.<Entities>().Any()` returns true. An empty list is returned if no entities are present.
- **SaveVariantFactory**:
- A single shared `PersistCalculator` instance is used across all save handlers.
- `SaveCustomChannels` and `SaveHardware` are instantiated regardless of whether data exists, but only added to `saveHandlers` if `Hardware().Any()` is true for `SaveHardware`.
- `SaveGroups` is only added to `saveHandlers` if `Groups().Any()` or `StaticGroups().Any()` is true.
- When `showCheckoutButton` is true, both `SaveTestSetup` and `SaveCheckoutTestSetup` are created for test setups.
- **XmlParserFactory**:
- The version threshold is `FileUtils.DataPRO20XmlVersion`. Versions below this use `LessThan20XMLVersion`; versions at or above use `GreaterOrEqual20XMLVersion`.
- `LessThan20XMLVersion` returns an empty list if `node` or `node.ChildNodes` is null.
- Unknown XML element names

View File

@@ -0,0 +1,70 @@
---
source_files:
- Common/DTS.Common.Import/ImportOptions/EqxImportOptions.cs
- Common/DTS.Common.Import/ImportOptions/CsvImportOptions.cs
generated_at: "2026-04-17T16:36:19.520206+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "edba9a74df78fb33"
---
# Documentation: DTS.Common.Import.ImportOptions
## 1. Purpose
This module defines configuration option classes for the DTS import subsystem. It provides strongly-typed containers for import behavior settings, specifically for EQX-format imports and CSV-format imports. These classes serve as parameter objects that control how data is parsed, validated, and persisted during import operations.
---
## 2. Public Interface
### `EqxImportOptions`
A configuration class for EQX-format imports.
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `OverwriteExistingSensors` | `bool` | `true` | Controls whether existing sensors should be overwritten during import. |
| `ImportSensorModels` | `bool` | `true` | Controls whether sensor models should be imported. |
---
### `CsvImportOptions`
A configuration class for CSV-format imports.
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `Encoding` | `string` | None (uninitialized) | Specifies the character encoding for parsing the CSV file. |
| `FieldSeparator` | `string` | None (uninitialized) | Specifies the delimiter character(s) used to separate fields. |
| `ImportCulture` | `CultureInfo` | None (uninitialized) | Specifies the culture settings for parsing culture-dependent values (e.g., number formats, dates). |
| `StripBackSlash` | `bool` | None (uninitialized) | Controls whether backslash characters should be removed during import. |
---
### `ZeroMethodOptions`
A configuration class for zero method settings (appears related to sensor calibration/offset handling).
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `ZeroMethodType` | `ZeroMethodType` | None (uninitialized) | Specifies the type of zero method to apply. |
| `ZeroMethodStart` | `double` | None (uninitialized) | Specifies the start value for the zero method range. |
| `ZeroMethodEnd` | `double` | None (uninitialized) | Specifies the end value for the zero method range. |
---
## 3. Invariants
- **EqxImportOptions**: Both boolean properties (`OverwriteExistingSensors`, `ImportSensorModels`) are always initialized to `true` by default.
- **CsvImportOptions**: No default values are enforced by the class; properties may be `null` if not explicitly set.
- **ZeroMethodOptions**: No default values are enforced by the class; properties may be `null` or `0` (for value types) if not explicitly set.
- No validation logic is present in these classes; any constraints must be enforced by consumers.
---
## 4. Dependencies
### This module depends on:
- `System` (core BCL types)
- `

View File

@@ -0,0 +1,87 @@
---
source_files:
- Common/DTS.Common.Import/Interfaces/IPersistImport.cs
- Common/DTS.Common.Import/Interfaces/IParseImport.cs
- Common/DTS.Common.Import/Interfaces/IParseVariant.cs
- Common/DTS.Common.Import/Interfaces/IParseCSVTest.cs
- Common/DTS.Common.Import/Interfaces/IParseCSVSensor.cs
- Common/DTS.Common.Import/Interfaces/ICalibrationImport.cs
- Common/DTS.Common.Import/Interfaces/ILockImport.cs
- Common/DTS.Common.Import/Interfaces/IGroupImport.cs
generated_at: "2026-04-17T16:02:47.396088+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "78f079bf5483238e"
---
# Interfaces
### Purpose
This module defines the core abstraction layer for the import subsystem, providing interfaces for parsing, persisting, locking, and grouping imported data. It establishes contracts for handling CSV-based test and sensor imports, calibration records, and database locking mechanisms during import operations. The interfaces enable a separation between import orchestration and concrete implementations.
### Public Interface
**IPersistImport**
- `void Save()` - Persists the current import state. No parameters; returns void.
**IParseImport**
- `ImportObject Parse(IEnumerable<string> importFiles)` - Parses a collection of file paths into an `ImportObject`. Accepts `IEnumerable<string>` of file paths.
**IParseVariant**
- `string FileName { get; set; }` - Property for the file name being parsed.
- `void Parse(ref ImportObject importObject)` - Parses variant data into the provided `ImportObject`. Note: `importObject` is passed by reference.
**IParseCSVTest**
- `int Version { get; }` - Read-only property indicating the parser version.
- `void ParseVersion(CsvReader csvReader, TestSetupImportData tsid)` - Parses version-specific test data using a `CsvReader` into `TestSetupImportData`.
**IParseCSVSensor**
- `int Version { get; }` - Read-only property indicating the parser version.
- `void Initialize(ICalibrationImport import, ZeroMethodOptions zmOptions, IImportNotification importNotification, bool importCreateDynamicGroups, bool useIsoCodeFilterMapping, bool useZeroForUnfiltered)` - Initializes the parser with calibration import, zero method options, notification handler, and various import flags.
- `void ParseVersion(CSVImportTags.Tags field, string val, ParseParameters pp)` - Parses a specific field/value pair for the current version.
**ICalibrationImport**
- `SensorCalibration AddLinearCalRecordIfNeeded(SensorCalibration sc, bool savedIsProportional, bool savedRemoveOffset)` - Adds a linear calibration record if conditions are met.
- `SensorCalibration AddLinearZeroMethodIfNeeded(SensorCalibration sc, ZeroMethodType zeroMethodType, double zeroMethodStart, double zeroMethodEnd)` - Adds a linear zero method to calibration if needed.
- `SensorCalibration CheckForExcitationCalibration(SensorCalibration sc, double sensitivity, ExcitationVoltageOptions.ExcitationVoltageOption excitation, string EU)` - Checks and configures excitation calibration.
**ILockImport**
- `bool Contended { get; }` - Returns true if the collection of contended locks has any items.
- `void SetLock(ref ImportObject importObject, ref StringBuilder message)` - Sets a database lock for the import object; errors populate the `StringBuilder` message.
- `void FreeLock(ref ImportObject importObject)` - Releases the database lock for the import object.
- `bool StealLock(bool proceed)` - Steals the database lock; returns success status.
**IGroupImport**
- `ParseParameters ParseParameters { get; set; }` - Property for parsing parameters.
- `Tuple<TestTemplate, List<IGroup>> CreateGroups(List<SensorData> sensors, Dictionary<string, List<TsetSetupImportSensorInfo>> groupSensorLookup, TestTemplate testTemplate, bool createDynamicGroups, List<IGroup> staticGroups, Action<double> setProgress)` - Creates groups from sensor data with progress reporting.
- `Dictionary<string, List<TsetSetupImportSensorInfo>> GetGroupSensorLookup(List<SensorData> sensors, Dictionary<string, string> sensorGroupNameLookup, Dictionary<string, List<string>> groupNameSensorListLookup)` - Builds a lookup dictionary mapping group names to sensor info.
### Invariants
- `IParseVariant.Parse` modifies `ImportObject` via reference; the caller must expect mutation.
- `ILockImport.SetLock` requires an empty `StringBuilder` to be passed in; it will be populated with errors if any occur.
- `IParseCSVSensor.Initialize` must be called before `ParseVersion` (implied by initialization pattern).
- `IUserDbRecord.UserName` must be unique (documented in interface comments, though this interface is in a different module).
### Dependencies
**Depends on:**
- `System.Collections.Generic` (IEnumerable, Dictionary, List)
- `System.Text` (StringBuilder)
- `CsvHelper` (CsvReader)
- `DTS.Common.Classes` (TestSetupImportData)
- `DTS.Common.Classes.Sensors` (SensorData)
- `DTS.Common.Enums` (ZeroMethodType)
- `DTS.Common.Enums.Sensors` (sensor-related enums)
- `DTS.Common.Import.ImportOptions` (ZeroMethodOptions)
- `DTS.Common.Interface.Groups.GroupList` (IGroup)
- `DTS.SensorDB` (SensorCalibration)
- `DataPROWin7.DataModel` (TestTemplate, TsetSetupImportSensorInfo)
**Depended on by:** Not determinable from source alone; these are interfaces consumed by implementations.
### Gotchas
- `IParseVariant.Parse` uses `ref ImportObject` while `IParseImport.Parse` returns a new `ImportObject`. This inconsistency suggests different ownership models.
- `ILockImport` has a comment referencing "FB 36740" indicating a feature request/bug tracking reference.
- The `ILockImport.StealLock` method's `proceed` parameter purpose is unclear from the signature alone.
- `IParseCSVSensor.ParseVersion` takes a `string val` parameter, suggesting string-based field values rather than typed parsing.
---

View File

@@ -0,0 +1,52 @@
---
source_files:
- Common/DTS.Common.Import/Parsers/ParseVariantBase.cs
- Common/DTS.Common.Import/Parsers/DefaultParseImport.cs
- Common/DTS.Common.Import/Parsers/DTSXMLParseImport.cs
generated_at: "2026-04-17T16:35:09.352474+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "98d94de856736199"
---
# Documentation: DTS.Common.Import Parsers
## 1. Purpose
This module provides parsing infrastructure for importing data files into the DTS system. It defines an abstract base class `ParseVariantBase` for creating file-specific parsers, and two concrete implementations of `IParseImport` (`DefaultParseImport` and `DTSXMLParseImport`) that orchestrate the parsing process using processor classes. The module supports extensibility through injected parse variants and handles specialized XML import scenarios including hardware relationship linking.
---
## 2. Public Interface
### ParseVariantBase (Abstract Class)
**Namespace:** `DTS.Common.Import.Parsers`
**Implements:** `IParseVariant`
| Member | Signature | Description |
|--------|-----------|-------------|
| `FileName` | `string { get; set; }` | Property to store the name of the file being parsed. |
| `Parse` | `abstract void Parse(ref ImportObject importObject)` | Abstract method that derived classes must implement to perform parsing logic. Receives `ImportObject` by reference. |
---
### DefaultParseImport (Class)
**Namespace:** `DTS.Common.Import.Parsers`
**Implements:** `IParseImport`
| Member | Signature | Description |
|--------|-----------|-------------|
| Constructor | `DefaultParseImport(ImportObject importObject, IEnumerable<IParseVariant> parseVariants)` | Initializes the parser with an import object and a collection of parse variants. |
| `Parse` | `ImportObject Parse(IEnumerable<string> importFiles)` | Orchestrates parsing by creating a `ParseProcessor` with the configured variants and files. Returns the processed `ImportObject`. |
---
### DTSXMLParseImport (Class)
**Namespace:** `DTS.Common.Import`
**Implements:** `IParseImport`
| Member | Signature | Description |
|--------|-----------|-------------|
| Constructor | `DTSXMLParseImport(ImportObject importObject, IImportNotification importNotification, Func<bool> isCancelled = null, bool skipNormalizing = false)` | Initializes the XML parser with notification support, optional cancellation callback, and optional normalization skip. |
| `UIItems` | `List<IUIItems> { get; set; }` | Property for UI items, assigned to the internal `XMLParseProcessor` during parsing. |
| `Parse`

View File

@@ -0,0 +1,182 @@
---
source_files:
- Common/DTS.Common.Import/Parsers/CSV/AbstractCSVParser.cs
- Common/DTS.Common.Import/Parsers/CSV/Version0CSVTestParser.cs
- Common/DTS.Common.Import/Parsers/CSV/CSVFile.cs
- Common/DTS.Common.Import/Parsers/CSV/Version6CSVTestParser.cs
- Common/DTS.Common.Import/Parsers/CSV/Version3CSVSensorParser.cs
- Common/DTS.Common.Import/Parsers/CSV/Version5CSVTestParser.cs
- Common/DTS.Common.Import/Parsers/CSV/Version4CSVSensorParser.cs
- Common/DTS.Common.Import/Parsers/CSV/CSVGroupImport.cs
- Common/DTS.Common.Import/Parsers/CSV/DTSCSVTestSetupParser.cs
- Common/DTS.Common.Import/Parsers/CSV/DTSCSVSensorsParser.cs
generated_at: "2026-04-17T15:31:35.696653+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "82eec24579c17b93"
---
# CSV Import Parsers Documentation
## 1. Purpose
This module provides CSV parsing functionality for importing DTS sensor configurations and test setups. It implements a versioned parser architecture where different CSV format versions (0-6) are handled by specialized parser classes. The module reads CSV files containing sensor metadata, calibration data, group assignments, and test setup configurations, transforming them into domain objects for the DTS data acquisition system. The architecture separates sensor parsing from test setup parsing, with both feeding into a group import system that creates the final test template structure.
---
## 2. Public Interface
### AbstractCSVParser (Abstract Base Class)
| Member | Signature | Description |
|--------|-----------|-------------|
| Version | `public abstract int Version { get; }` | Returns the parser version number this class handles |
| Initialize | `public void Initialize(ICalibrationImport import, ZeroMethodOptions zmOptions, IImportNotification importNotification, bool importCreateDynamicGroups, bool useISOCodeFilterMapping, bool useZeroForUnfiltered)` | Initializes the parser with dependencies and configuration flags |
| ParseVersion | `public abstract void ParseVersion(CSVImportTags.Tags field, string val, ParseParameters pp)` | Parses a specific field value for this parser's version |
### Version0CSVTestParser
| Member | Signature | Description |
|--------|-----------|-------------|
| Version | `public int Version => 0` | Returns version 0 |
| ParseVersion | `public void ParseVersion(CsvReader csvReader, TestSetupImportData tsid)` | Parses version 0 test setup data including PostTriggerSec, PreTriggerSec, RecordingMode, SampleRate, Description, Name, Version, and Tags |
### Version5CSVTestParser
| Member | Signature | Description |
|--------|-----------|-------------|
| Version | `public int Version => 5` | Returns version 5 |
| ParseVersion | `public void ParseVersion(CsvReader csvReader, TestSetupImportData tsid)` | Parses version 5 test setup data including clock configuration (ClockMasterInputType, ClockMasterOutputType, ClockSlaveInputType, ClockSlaveOutputType, ManageClocksOutsideDPMaster, ManageClocksOutsideDPSlave) |
### Version6CSVTestParser
| Member | Signature | Description |
|--------|-----------|-------------|
| Version | `public int Version => 6` | Returns version 6 |
| ParseVersion | `public void ParseVersion(CsvReader csvReader, TestSetupImportData tsid)` | Parses version 6 test setup data including DAS hardware info (DASSerial, DASSampleRate, PTPDomainId, ClockMaster) with multi-row body parsing |
### Version3CSVSensorParser
| Member | Signature | Description |
|--------|-----------|-------------|
| Version | `public override int Version => 3` | Returns version 3 |
| ParseVersion | `public override void ParseVersion(CSVImportTags.Tags field, string sVal, ParseParameters pp)` | Parses GroupName and GroupType fields with duplicate detection and test object validation |
### Version4CSVSensorParser
| Member | Signature | Description |
|--------|-----------|-------------|
| Version | `public override int Version => 4` | Returns version 4 |
| ParseVersion | `public override void ParseVersion(CSVImportTags.Tags field, string sVal, ParseParameters pp)` | Parses DAS assignment (DASSerialNumber, DASChannelIndex), UDP streaming (StreamProfile, UDPAddress, TimeChannelId, DataChannelId, TmNSConfig, IRIGTimeDataPacketIntervalMS, TMATSIntervalMS), UART configuration (BaudRate, DataBits, StopBits, Parity, DataFormat), and user codes (TestUserCode, TestUserChannelName, TestIsoCode, TestIsoChannelName) |
### CSVFile
| Member | Signature | Description |
|--------|-----------|-------------|
| Constructor | `public CSVFile(string filename)` | Creates instance with specified filename |
| IsInUse | `public static bool IsInUse(string filename)` | Returns true if file is locked/in use by another process |
| IsCSVFileForTestSetupImport | `public static bool IsCSVFileForTestSetupImport(string filename, CsvImportOptions csvImportOptions)` | Validates if CSV file is formatted for test setup import (checks for "Version" header) |
| GetCsvVersion | `public static int GetCsvVersion(string filename)` | Extracts and returns the version number from CSV file, returns 0 on error |
| LineCount | `public int LineCount { get; }` | Returns the number of lines in the file |
### CSVGroupImport
| Member | Signature | Description |
|--------|-----------|-------------|
| ParseParameters | `public ParseParameters ParseParameters { get; set; }` | Gets or sets the parse parameters for import |
| CreateGroups | `public Tuple<TestTemplate, List<IGroup>> CreateGroups(List<SensorData> sensors, Dictionary<string, List<TsetSetupImportSensorInfo>> groupSensorLookup, TestTemplate testTemplate, bool createDynamicGroups, List<IGroup> staticGroups, Action<double> setProgress)` | Creates groups and channels from sensor data, populating the test template |
| GetGroupSensorLookup | `public Dictionary<string, List<TsetSetupImportSensorInfo>> GetGroupSensorLookup(List<SensorData> sensors, Dictionary<string, string> sensorGroupNameLookup, Dictionary<string, List<string>> groupNameSensorListLookup)` | Builds lookup dictionary mapping group names to sensor info lists |
### DTSCSVTestSetupParser
| Member | Signature | Description |
|--------|-----------|-------------|
| Constructor | `public DTSCSVTestSetupParser(IImportNotification importNotification, CsvImportOptions csvImportOptions, TestSetupImportData testSetupImportData, IGroupImport groupImport, bool createDynamicGroups)` | Initializes parser with dependencies |
| CreateTestSetup | `public static TestTemplate CreateTestSetup(TestSetupImportData tsid, DASHardware[] allDAS)` | Creates a TestTemplate from parsed import data |
| UpdateDASSampleRate | `public static void UpdateDASSampleRate(TestTemplate t, TestSetupImportData tsid, DASHardware[] allDAS)` | Updates sample rates for DAS hardware in the test template |
| Parse | `public override void Parse(ref ImportObject importObject)` | Main entry point - parses CSV file and populates ImportObject with test setup data |
### DTSCSVSensorsParser
| Member | Signature | Description |
|--------|-----------|-------------|
| Constructor | `public DTSCSVSensorsParser(IImportNotification importNotification, User user, CsvImportOptions csvImportOptions, ICalibrationImport calibrationImport, ZeroMethodOptions zeroMethodOptions)` | Initializes parser with dependencies |
| ImportCreateDynamicGroups | `public bool ImportCreateDynamicGroups { get; set; }` | Flag for dynamic group creation during import |
| UseISOCodeFilterMapping | `public bool UseISOCodeFilterMapping { get; set; }` | Flag for ISO code filter mapping behavior |
| UseZeroForUnfiltered | `public bool UseZeroForUnfiltered { get; set; }` | Flag for using zero values for unfiltered data |
| Parse | `public override void Parse(ref ImportObject importObject)` | Main entry point - parses CSV file and populates ImportObject with sensor and calibration data |
---
## 3. Invariants
1. **Version Header Requirement**: CSV files must have "Version" as the first token in the first row to be recognized as valid for import.
2. **Version-Based Parser Selection**: The `CSVImportTags.GetVersionForTag()` determines which parser handles each field. Parsers only process fields matching their version.
3. **Version 6 Multi-Parser Execution**: When `tsid.Version == 6`, all parsers from index 1 through the array length are invoked sequentially (see `DTSCSVTestSetupParser.ParseTestSetup`).
4. **Duplicate Serial Number Detection**: `Version3CSVSensorParser` enforces unique sensor serial numbers within `SensorGroupNameLookup` and `SensorGroupTypeLookup` dictionaries.
5. **Non-Empty Group Names**: Group names must be non-empty and non-whitespace; empty values generate errors.
6. **Test Setup Name Uniqueness**: Import skips test setups with names that already exist in `importObject.TestSetups()`.
7. **Calibration Assignment Order**: Calibrations are sorted and the most recent (last element after sort) is assigned to each sensor.
8. **Analog Sensor Validation**: Analog sensors require non-zero sensitivity and capacity >= 1; violations generate errors.
9. **Excitation Validation**: Full/Half/Quarter bridge sensors require defined excitation voltage (not `Undefined`).
---
## 4. Dependencies
### External Dependencies (Imports)
| Namespace | Purpose |
|-----------|---------|
| `CsvHelper` | CSV file reading via `CsvReader` |
| `DTS.Common.Classes.Sensors` | `SensorData`, `SensorCalibration`, `ParseParameters` |
| `DTS.Common.Enums.Sensors` | Sensor enumerations including `BridgeType`, `SensUnits`, `ExcitationVoltageOptions` |
| `DTS.Common.Import.ImportOptions` | `CsvImportOptions`, `ZeroMethodOptions` |
| `DTS.Common.Import.Interfaces` | `IParseCSVSensor`, `IParseCSVTest`, `ICalibrationImport`, `IImportNotification`, `IGroupImport` |
| `DTS.Common.Import.Factories` | `CSVTestParserFactory`, `CSVSensorParserFactory` |
| `DTS.Common.Import.Parsers` | `ParseVariantBase` base class |
| `DTS.Common.Storage` | `DbOperations` for database access |
| `DTS.SensorDB` | Database operations |
| `DataPROWin7.DataModel.Classes.Hardware` | `DASHardwareList` for hardware enumeration |
| `System.IO.Ports` | `StopBits`, `Parity` enumerations for UART configuration |
| `DTS.Slice.Users` | `User` class for current user context |
| `DTS.Common.Utilities.Logging` | `APILogger` for error logging |
### Consumers (Inferred)
The module implements interfaces (`IParseCSVSensor`, `IParseCSVTest`, `IGroupImport`) and extends `ParseVariantBase`, suggesting consumption via:
- Factory patterns (`CSVTestParserFactory`, `CSVSensorParserFactory`)
- Dependency injection through interface types
- The `ImportObject` pattern which aggregates parsed results
---
## 5. Gotchas
1. **Version 6 Special Execution Path**: Unlike other versions, version 6 triggers iteration through all parsers starting at index 1:
```csharp
if (tsid.Version == 6)
{
for (var i = 1; i < parsers.Length; i++)
{
parsers[i].ParseVersion(parser, tsid);
}
}
```
This means version 6 files are processed by multiple parsers, not just `Version6CSVTestParser`.
2. **Silent Sensitivity Unit Correction**: Non-proportional sensors with `SensUnits.mVperVperEU` are silently corrected to `SensUnits.mVperEU`. Users are notified via `_importNotification.ReportErrors` but parsing continues.
3. **ISO Channel-Only Prefix Bypass**: Sensors with serial numbers starting with `Constants.ISO_CH_ONLY_PREFIX` are excluded from `AddSensorLookup` and `AddCalibrationLookup` calls, but still added via `AddSensor` and `AddCalibration`.
4. **Exception Swallowing in CSVFile**:
- `IsInUse()` suppresses all non-IOException exceptions
- `IsCSVFileForTestSetupImport()` and `GetCsvVersion()` catch all exceptions and return `false`/`0`
5. **Generic Exception in Version3CSVSensorParser**: Throws `new Exception("Parse error")` when a group maps to multiple test objects and `ImportCreateDynamicGroups` is false. This breaks the pattern of adding errors to `pp.Errors`.
6. **Dual Sample Rate Storage**: The comment in `UpdateDASSampleRate` explicitly notes uncertainty about why sample rates are stored in both `t.SetSampleRateForHardware()` and `t.DASSampleRateList[]`.
7. **Historical Bug References**: Comments reference "FB" tracking numbers (e.g., "FB 40598", "FB 36879", "FB 43815") indicating accumulated fixes. These may indicate areas with historical issues.
8. **Range Assignment Complexity**: The range assignment logic in `CSVGroupImport.CreateGroups` has specific conditions involving `ImportContainedSensorRanges`, `RangeHigh`, `RangeLow`, `RangeMedium`, and `Capacity` that may produce unexpected results if not fully understood.
9. **Version 6 Header Search Loop**: `Version6CSVTestParser` and `Version5CSVTestParser` both skip rows until finding a version-appropriate tag, but use different version checks (6 vs 5). This could cause confusion if tags overlap.

View File

@@ -0,0 +1,175 @@
---
source_files:
- Common/DTS.Common.Import/Parsers/EQX/EQXTestSetupParser.cs
- Common/DTS.Common.Import/Parsers/EQX/EQXGroupImport.cs
- Common/DTS.Common.Import/Parsers/EQX/EQXSensorsParser.cs
generated_at: "2026-04-17T15:39:25.870361+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "605a991ac1639306"
---
# EQX Import Parsers Documentation
## 1. Purpose
This module provides parsing functionality for importing Equipment Exchange (EQX) format files into the DTS system. It consists of three main components: `EQXTestSetupParser` for importing test setup configurations including groups and channel assignments, `EQXSensorsParser` for importing sensor definitions and calibration data, and `EQXGroupImport` for processing group-to-sensor mappings during test setup creation. The module bridges the proprietary EQX XML format with the internal DTS data model, handling version compatibility, calibration assignments, and group hierarchy construction.
---
## 2. Public Interface
### EQXTestSetupParser
**Constructor:**
```csharp
public EQXTestSetupParser(
IImportNotification importNotification,
EqxImportOptions eqxImportOptions,
IGroupImport groupImport,
EquipmentExchange.EQXSensorDatabase eqxSensorDatabase,
bool createDynamicGroups)
```
Initializes the parser with notification services, import options, group import handler, sensor database reference, and a flag indicating whether dynamic groups should be created.
**Methods:**
```csharp
public override void Parse(ref ImportObject importObject)
```
Parses the EQX file specified by `FileName` (inherited from `ParseVariantBase`) and populates the `importObject` with test setup data. Validates that group name test object lookup exists; if not, adds a critical error and aborts. Assigns group lookups, creates test templates, fixes calibrations, assigns groups to test setup, and sets the `TestSetupImportFileFormat` on the import object.
---
### EQXGroupImport
**Implements:** `IGroupImport`
**Properties:**
```csharp
public ParseParameters ParseParameters { get; set; }
```
**Methods:**
```csharp
public Tuple<TestTemplate, List<IGroup>> CreateGroups(
List<SensorData> sensors,
Dictionary<string, List<TsetSetupImportSensorInfo>> groupSensorLookup,
TestTemplate testTemplate,
bool createDynamicGroups,
List<IGroup> staticGroups,
Action<double> setProgress)
```
Creates groups from the provided sensor data and group-sensor lookup. Returns a tuple containing the populated `TestTemplate` and list of static groups. Returns `null` if `groupSensorLookup` is null or empty. Groups are sorted by sensor count (descending), then by name (ascending). Each group is populated with `GroupChannel` objects containing sensor data, calibration info, squib settings, and digital I/O configuration.
```csharp
public Dictionary<string, List<TsetSetupImportSensorInfo>> GetGroupSensorLookup(
List<SensorData> sensors,
Dictionary<string, string> sensorGroupNameLookup,
Dictionary<string, List<string>> groupNameSensorListLookup)
```
Builds a lookup dictionary mapping group names to lists of `TsetSetupImportSensorInfo`. Handles two mutually exclusive input formats: `sensorGroupNameLookup` (sensor → group name) or `groupNameSensorListLookup` (group name → list of sensor serial numbers).
---
### EQXSensorsParser
**Constructor:**
```csharp
public EQXSensorsParser(
IImportNotification importNotification,
User user,
EqxImportOptions eqxImportOptions,
EquipmentExchange.EQXSensorDatabase eqxSensorDatabase)
```
**Constants:**
```csharp
const float MAX_EQX_VERSION_SUPPORT = 1.5F;
```
**Properties:**
```csharp
public bool ImportCreateDynamicGroups { get; set; }
public bool EQXUseSerialNumberFieldForSN { get; set; }
public bool UseZeroForUnfiltered { get; set; }
```
**Methods:**
```csharp
public override void Parse(ref ImportObject importObject)
```
Parses the EQX file for sensor data. Validates XML structure and EQX format version (must be ≤ 1.5). Delegates to `ParseSensor` for actual processing.
---
## 3. Invariants
- **EQX Version Compatibility:** The maximum supported EQX DataFormatEdition is `1.5F`. Files with higher versions will cause import rejection with an error message.
- **Null ImportObject Handling:** Both `EQXTestSetupParser.Parse()` and `EQXSensorsParser.Parse()` throw `ArgumentNullException` if `importObject` is null.
- **Empty FileName Handling:** Both parsers return immediately without processing if `FileName` is null or empty.
- **Group Lookup Mutual Exclusivity:** In `EQXGroupImport.GetGroupSensorLookup()`, either `sensorGroupNameLookup` OR `groupNameSensorListLookup` will be populated, but not both (per comment FB 30358).
- **Calibration Assignment:** In `FixCalibrations()`, calibrations are sorted and the first calibration (index 0) is assigned to each sensor.
- **Test Setup Uniqueness:** `EQXTestSetupParser.Parse()` returns early without creating a test setup if a test setup with the same name already exists in `importObject.TestSetups()`.
- **Group Sorting:** Groups are sorted by sensor count descending, then alphabetically by name ascending when equal.
- **Channel Order:** `GroupChannelOrder` and `TestSetupOrder` are 1-indexed (1 + sensor index).
---
## 4. Dependencies
### Direct Dependencies (Imports):
**EQXTestSetupParser:**
- `DataPROWin7.DataModel` - `ImportObject`, `ImportError`, `ImportSeverityError`, `TestTemplate`, `SensorData`
- `DTS.Common.Import.ImportOptions` - `EqxImportOptions`
- `DTS.Common.Import.Parsers` - `ParseVariantBase`
- `DTS.Common.Interface.Groups.GroupList` - `IGroupImport`, `IGroup`
- `DTS.Common.SharedResource.Strings` - `StringResources`
- `DTS.Common.Utilities.Logging` - `APILogger`
- `DTS.Common.Utils` - `GroupHelper`
- `DTS.SensorDB` - `EquipmentExchange.EQXSensorDatabase`
- `System.Xml.Linq` - XML parsing
**EQXGroupImport:**
- `DataPROWin7.DataModel` - `SensorData`, `TestTemplate`, `TsetSetupImportSensorInfo`
- `DTS.Common.Classes.Groups` - Group-related classes
- `DTS.Common.Classes.Sensors` - `GroupChannel`
- `DTS.Common.Interface.Groups.GroupList` - `IGroupImport`, `IGroup`
- `DTS.Common.Storage` - `DbOperations`
- `DTS.SensorDB` - Sensor database types
**EQXSensorsParser:**
- `DataPROWin7.DataModel` - `ImportObject`, `SensorData`
- `DTS.Common.Enums` - Enumerations including `BridgeType`, `ExcitationVoltageOptions`, `SquibMeasurementType`
- `DTS.Common.Import.ImportOptions` - `EqxImportOptions`
- `DTS.Common.Import.Parsers` - `ParseVariantBase`
- `DTS.Common.Storage` - `DbOperations`
- `DTS.Common.Classes.Sensors` - `FactorySensorModel`, `SensorsCollection`
- `DTS.Common.Interface.Sensors` - `ISensorData`
- `DTS.Common.SharedResource.Strings` - `StringResources`
- `DTS.Slice.Users` - `User`
- `DTS.SensorDB` - `EquipmentExchange.EQXSensorDatabase`
- `System.Xml.Linq` - XML parsing
### Consumers:
- The module is consumed by the DTS import system (exact consumers not visible in provided source).
---
## 5. Gotchas
### Calibration Reset Issue (FB 44105 / Historical Bug)
The comment in `EQXTestSetupParser.AssignGroupsToTestSetup()` references a bug where `GroupHelper.NormalizeSensorIds()` can reset calibrations for sensors. The workaround is calling `FixCalibrations(importObject)` immediately after normalization to restore calibrations from the import data.
### Duplicate Calibration Fix Calls
`FixCalibrations()` is called twice in `EQXTestSetupParser.Parse()`: once early in the method, and again inside `AssignGroupsToTestSetup()` after `NormalizeSensorIds()`. This is intentional due to the normalization side-effect noted above.
### EID Preservation (Bug 18467)
`EQXSensorsParser.ParseSensor()` contains special logic to preserve existing EID values when the EQX file has a NULL `IDModuleString`. Without this, importing an EQX file with missing IDModuleString would clear the EID on existing sensors.
### Null IDModule Handling
The method `SensorHasNullIDModule()` and `GetSensorNullIdModuleValue()` are called on `_eq

View File

@@ -0,0 +1,365 @@
---
source_files:
- Common/DTS.Common.Import/Persist/SaveServer.cs
- Common/DTS.Common.Import/Persist/SaveGroupTemplates.cs
- Common/DTS.Common.Import/Persist/SaveVariantBase.cs
- Common/DTS.Common.Import/Persist/SaveGlobalSettings.cs
- Common/DTS.Common.Import/Persist/PersistCalculator.cs
- Common/DTS.Common.Import/Persist/SaveSensorModels.cs
- Common/DTS.Common.Import/Persist/SaveTestEngineerDetails.cs
- Common/DTS.Common.Import/Persist/SaveLabDetails.cs
- Common/DTS.Common.Import/Persist/SaveUsers.cs
- Common/DTS.Common.Import/Persist/SaveCustomerDetails.cs
- Common/DTS.Common.Import/Persist/SaveHardware.cs
- Common/DTS.Common.Import/Persist/SaveTestSetupHelper.cs
- Common/DTS.Common.Import/Persist/SaveGroups.cs
- Common/DTS.Common.Import/Persist/SaveCustomChannels.cs
- Common/DTS.Common.Import/Persist/SaveTestSetup.cs
- Common/DTS.Common.Import/Persist/SaveCheckoutTestSetup.cs
generated_at: "2026-04-17T15:28:30.641712+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "85e93f86bc467691"
---
# DTS.Common.Import.Persist Module Documentation
## 1. Purpose
This module implements the persistence layer for importing various data entities into the DTS (Data Test System). It provides a Strategy pattern implementation where each `SaveVariantBase` subclass handles persisting a specific entity type (hardware, users, test setups, groups, sensors, etc.) to the database. The module coordinates progress tracking, cancellation support, and ID remapping between old imported identifiers and newly assigned database identifiers.
---
## 2. Public Interface
### SaveVariantBase (Abstract Base Class)
```csharp
public abstract class SaveVariantBase : IPersistImport
{
protected ImportObject _importObject;
protected readonly IPersistCalculator _persistCalculator;
protected readonly IImportNotification _importNotification;
protected readonly Func<bool> IsCancelled;
protected SaveVariantBase(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, Func<bool> isCancelled = null)
public abstract void Save();
}
```
Base class for all save variants. Provides shared infrastructure for progress notification and cancellation.
---
### PersistCalculator
```csharp
public class PersistCalculator : IPersistCalculator
{
public double ProgressValue { get; } // Returns _done / _total
public void AddDone() // Increments _done by 1
public void AddDone(double value) // Increments _done by value
public void AddToTotal(double value) // Adds to _total (throws if value < 0)
}
```
Calculates import progress as a ratio of completed work to total work.
---
### SaveHardware
```csharp
public class SaveHardware : SaveVariantBase
{
public Dictionary<int, int> OldDASIdToNewDASId { get; set; }
public Dictionary<int, List<IISOHardware>> TestIdToHardware { get; set; }
public SaveHardware(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, Func<bool> isCancelled = null)
public override void Save()
}
```
Persists hardware entities. Tracks DAS ID remapping and hardware-to-test relationships for downstream consumers.
---
### SaveGroups
```csharp
public class SaveGroups : SaveVariantBase
{
public bool CanCurrentUserCommitChannelCodes { get; set; } = true;
public IChannelSetting DefaultZeroMethod { get; set; }
public IChannelSetting DefaultZeroStart { get; set; }
public IChannelSetting DefaultZeroEnd { get; set; }
public IChannelSetting DefaultInitialOffset { get; set; }
public Dictionary<int?, int> OldGroupIdToNewGroupId { get; set; }
public SaveGroups(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, SaveHardware saveHardware,
Func<bool> isCancelled = null)
public override void Save()
}
```
Persists static groups. Requires `SaveHardware` instance for DAS ID remapping. Updates sensor IDs and fixes missing zero method parameters.
---
### SaveCustomChannels
```csharp
public class SaveCustomChannels : SaveVariantBase
{
public ISO13499FileDb IsoDb { get; set; }
public Dictionary<string, string> CustomChannelTextIdToOldChannelId { get; set; }
public Dictionary<string, TestObjectChannel> CustomChannelOldChannelIdToChannel { get; set; }
public SaveCustomChannels(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, Func<bool> isCancelled = null)
public override void Save()
}
```
Persists custom channels with complex ID remapping logic. Maintains mappings for level trigger updates in test setups.
---
### SaveTestSetup
```csharp
public class SaveTestSetup : SaveVariantBase
{
public User CurrentUser { get; set; }
public string TestSetupName { get; set; }
public SaveTestSetup(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, SaveCustomChannels saveCustomChannels,
SaveHardware saveHardware, SaveGroups saveGroups, Func<bool> isCancelled = null)
public override void Save()
}
```
Persists test setups. Requires `SaveCustomChannels`, `SaveHardware`, and `SaveGroups` for cross-entity ID resolution.
---
### SaveCheckoutTestSetup
```csharp
public class SaveCheckoutTestSetup : SaveVariantBase
{
public User CurrentUser { get; set; }
public SaveCheckoutTestSetup(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, SaveCustomChannels saveCustomChannels,
SaveHardware saveHardware, SaveGroups saveGroups,
Func<bool> isCancelled = null, string setupName = null)
public override void Save()
}
```
Persists checkout-mode test setups with different default configuration than `SaveTestSetup`.
---
### SaveUsers
```csharp
public class SaveUsers : SaveVariantBase
{
public IUIItems[] UIItems { get; set; }
public User CurrentUser { get; set; }
public SaveUsers(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, Func<bool> isCancelled = null)
public override void Save()
}
```
Persists users. Requires `CurrentUser.IsAdmin` to be true (asserted via `Trace.Assert`).
---
### SaveSensorModels
```csharp
public class SaveSensorModels : SaveVariantBase
{
public User CurrentUser { get; set; }
public SaveSensorModels(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, Func<bool> isCancelled = null)
public override void Save()
}
```
Persists sensor models via `SensorModelCollection.SensorModelList.Commit()`.
---
### SaveGlobalSettings
```csharp
public class SaveGlobalSettings : SaveVariantBase
{
public SaveGlobalSettings(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, Func<bool> isCancelled = null)
public override void Save()
}
```
Persists global settings via `SettingsDB.SetGlobalValue()`.
---
### SaveTestEngineerDetails
```csharp
public class SaveTestEngineerDetails : SaveVariantBase
{
public SaveTestEngineerDetails(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, Func<bool> isCancelled = null)
public override void Save()
}
```
Persists test engineer details via `TestEngineerDetailsList.TestEngineerList.AddTestEngineer()`.
---
### SaveLabDetails
```csharp
public class SaveLabDetails : SaveVariantBase
{
public SaveLabDetails(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, Func<bool> isCancelled = null)
public override void Save()
}
```
Persists laboratory details. Skips invalid/blank entries via `IsInvalidBlank()` check.
---
### SaveCustomerDetails
```csharp
public class SaveCustomerDetails : SaveVariantBase
{
public SaveCustomerDetails(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, Func<bool> isCancelled = null)
public override void Save()
}
```
Persists customer details. Skips invalid/blank entries via `IsInvalidBlank()` check.
---
### SaveGroupTemplates
```csharp
public class SaveGroupTemplates : SaveVariantBase
{
public SaveGroupTemplates(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, Func<bool> isCancelled = null)
public override void Save()
}
```
Iterates group templates and updates progress. **Note: Does not appear to persist any data to database.**
---
### SaveServer
```csharp
class SaveServer : SaveVariantBase
{
public SaveServer(ImportObject importObject, IPersistCalculator persistCalculator,
IImportNotification importNotification, Func<bool> isCancelled = null)
public override void Save() // Throws NotImplementedException
}
```
Stub implementation. **Not implemented.**
---
### SaveTestSetupHelper (Static Helper)
```csharp
public static class SaveTestSetupHelper
{
public static void AddHardwareFromEmbeddedGroups(TestTemplate t, SaveGroups saveGroups,
List<int> hardwareRemoved, List<int> hardwareIncluded)
public static void FixDasAff(Dictionary<string, DASHardware> hardwareLookup, TestTemplate t)
public static Dictionary<string, DASHardware> PopulateHarwareLookup()
public static void DeleteExistingTestSetups(IEnumerable<TestTemplate> testSetups, string userName)
public static void UpdateLevelTriggers(ref Dictionary<string, string> oldIdToNewIdLookup,
SaveCustomChannels saveCustomChannels, IEnumerable<TestTemplate> testSetups)
}
```
Shared utility methods for test setup persistence operations.
---
## 3. Invariants
1. **Progress Calculation**: `ProgressValue` is calculated as `_done / _total`. If `_total` is 0, this will result in division by zero (not guarded against).
2. **AddToTotal Validation**: `PersistCalculator.AddToTotal(double value)` throws `ArgumentOutOfRangeException` if `value < 0`. The exception message states "value should not be less or equal to zero" but the check is only for `< 0`, not `<= 0`.
3. **Cancellation Default**: If `isCancelled` parameter is null, `IsCancelled` defaults to `() => false`, meaning the operation will never be cancelled.
4. **SaveUsers Admin Requirement**: `SaveUsers.Save()` asserts `CurrentUser.IsAdmin` must be true via `Trace.Assert`. This is a debug-only assertion, not a runtime exception.
5. **SaveHardware ID Tracking**: `OldDASIdToNewDASId` only contains entries when `h.DASId != oldId` after commit. Unchanged IDs are not tracked.
6. **SaveGroups Dependency**: `SaveGroups` requires a `SaveHardware` instance in its constructor to access `OldDASIdToNewDASId` for channel DAS ID remapping.
7. **SaveTestSetup/SaveCheckoutTestSetup Dependencies**: Both require `SaveCustomChannels`, `SaveHardware`, and `SaveGroups` instances for cross-entity ID resolution.
8. **Hardware Sort Order**: `SaveHardware.Save()` calls `.Sort()` on the hardware list before processing, implying hardware must implement `IComparable`.
---
## 4. Dependencies
### External Dependencies (Inferred from Imports)
| Module | Dependencies |
|--------|--------------|
| `SaveHardware` | `DataPROWin7.DataModel.Classes.Hardware`, `DTS.Common.Interface.DASFactory.Diagnostics`, `DTS.Common.SharedResource.Strings` |
| `SaveGroups` | `DataPROWin7.DataModel.Classes.Hardware`, `DTS.Common.Classes.Groups.ChannelSettings`, `DTS.Common.Interface.Channels`, `DTS.Common.Interface.Groups.GroupList`, `DTS.Common.SharedResource.Strings`, `DTS.Common.Storage` |
| `SaveCustomChannels` | `DataPROWin7.DataModel`, `DTS.Common.ISO` |
| `SaveTestSetup`, `SaveCheckoutTestSetup` | `DataPROWin7.DataModel`, `DataPROWin7.DataModel.Classes.Hardware`, `DTS.SensorDB`, `DTS.Slice.Users` |
| `SaveUsers` | `DTS.Slice.Users` |
| `SaveSensorModels` | `DTS.SensorDB`, `DTS.Slice.Users` |
| `SaveGlobalSettings` | `DTS.Common.Settings` |
| `SaveTestEngineerDetails`, `SaveLabDetails`, `SaveCustomerDetails` | `DataPROWin7.DataModel`, `DTS.Common.Import.Enums` |
| `SaveVariantBase` | `DTS.Common.Import.Interfaces` |
### Internal Dependencies
- All save variants depend on `ImportObject`, `IPersistCalculator`, and `IImportNotification`
- `SaveTestSetup`, `SaveCheckoutTestSetup` depend on `SaveCustomChannels`, `SaveHardware`, `SaveGroups`
- `SaveGroups` depends on `SaveHardware`
- `SaveTestSetupHelper` depends on `SaveGroups`, `SaveCustomChannels`
---
## 5. Gotchas
1. **SaveServer Not Implemented**: `SaveServer.Save()` throws `NotImplementedException`. This class should not be used in production.
2. **SaveGroupTemplates No Persistence**: `SaveGroupTemplates.Save()` iterates through group templates and updates progress but does not appear to commit any data to the database.
3. **Copy-Paste Error in SaveCustomerDetails**: The status is set to `ImportExtraStatus.ReadingLabDetails` instead of a customer-specific status. This appears to be a copy-paste error from `SaveLabDetails`.
4. **Division by Zero Risk**: `PersistCalculator.ProgressValue` does not guard against `_total` being zero, which would cause division by zero.
5. **Debug-Only Admin Check**: `SaveUsers` uses `Trace.Assert` for admin validation, which only fires in debug builds. In release builds, a non-admin user could attempt the import without exception.
6. **Invalid Details Tracking**: `SaveLabDetails` and `SaveCustomerDetails` set local `invalidLabDetails`/`invalidCustomerDetails` flags when encountering invalid entries, but these flags are never used or reported.
7. **Hardware List Mutation**: `SaveHardware.Save()` calls `.ToList().Sort()` on `_importObject.Hardware()`, which may have side effects on the underlying collection depending on implementation.
8. **Missing Error Reporting**: `SaveTestSetup.Save()` and `SaveCheckoutTestSetup.Save()` check `if (_importObject.Errors().Any())` but the body is empty with only a comment `//report errors`.
9. **Typo in Method Name**: `SaveTestSetupHelper.PopulateHarwareLookup()` is misspelled (should be "Hardware").
10. **GC.Collect Commented Out**: In `SaveCustomChannels.Save()`, there is a commented-out `GC.Collect()` with a comment acknowledging it as a "critical code smell" (referencing bug #11287 for out-of-memory exceptions with large CSV files).

View File

@@ -0,0 +1,38 @@
---
source_files:
- Common/DTS.Common.Import/Properties/AssemblyInfo.cs
generated_at: "2026-04-17T16:26:29.254875+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "c2705a8c6698fe06"
---
# Properties
### Purpose
This module contains assembly metadata for the `DTS.DAS.Concepts` assembly. It is a build-time configuration file that defines version information, copyright, and COM visibility settings for the assembly. It does not contain executable logic or types.
### Public Interface
No public types, functions, or methods are defined in this module. The file contains only assembly-level attributes:
- `AssemblyTitle`: Set to `"DTS.DAS.Concepts"`
- `AssemblyDescription`: Empty
- `AssemblyCompany`: `"DTS"`
- `AssemblyProduct`: `"DTS.DAS.Concepts"`
- `AssemblyCopyright`: `"Copyright © DTS 2008"`
- `ComVisible`: `false`
- `Guid`: `"9b6f7402-27d3-4cc9-9ff3-3cfe16e0b429"`
- `AssemblyVersion`: `"1.06.0081"`
- `AssemblyFileVersion`: `"1.06.0081"`
### Invariants
- COM visibility is explicitly set to `false`, meaning types in this assembly are not visible to COM components by default.
- The assembly version and file version are synchronized at `"1.06.0081"`.
### Dependencies
- **Depends on**: `System.Reflection`, `System.Runtime.InteropServices` (standard .NET Framework assemblies).
- **Depended on by**: Cannot be determined from this file alone.
### Gotchas
- The `AssemblyTitle` attribute value (`"DTS.DAS.Concepts"`) differs from the module path name (`DTS.Common.DAS.Concepts`). This discrepancy may cause confusion when referencing the assembly.
---

View File

@@ -0,0 +1,297 @@
---
source_files:
- Common/DTS.Common.Import/XML/XMLPre20ParseGroupTemplates.cs
- Common/DTS.Common.Import/XML/XMLParseMMECustomDirections.cs
- Common/DTS.Common.Import/XML/XMLParseMMECustomTestObjects.cs
- Common/DTS.Common.Import/XML/XMLParseMMECustomPositions.cs
- Common/DTS.Common.Import/XML/XMLParseMMECustomFineLoc3s.cs
- Common/DTS.Common.Import/XML/XMLParseMMECustomFineLoc2s.cs
- Common/DTS.Common.Import/XML/XMLParseMMECustomFineLoc1s.cs
- Common/DTS.Common.Import/XML/XMLParseSensorModels.cs
- Common/DTS.Common.Import/XML/XMLParseMMECustomFilterClasses.cs
- Common/DTS.Common.Import/XML/XMLParseMMECustomChannels.cs
- Common/DTS.Common.Import/XML/XMLParseMMECustomMainLocations.cs
- Common/DTS.Common.Import/XML/XMLParseMMECustomPhysicalDimensions.cs
- Common/DTS.Common.Import/XML/XMLPre20ParseSensors.cs
- Common/DTS.Common.Import/XML/XMLParseUsers.cs
- Common/DTS.Common.Import/XML/XMLParseBase.cs
- Common/DTS.Common.Import/XML/XMLParseTestEngineerDetails.cs
- Common/DTS.Common.Import/XML/XMLParseLabDetails.cs
- Common/DTS.Common.Import/XML/XMLParseGlobalSettings.cs
- Common/DTS.Common.Import/XML/XMLPre20ParseDASList.cs
- Common/DTS.Common.Import/XML/XMLParseCustomerDetails.cs
- Common/DTS.Common.Import/XML/XMLParseSensors.cs
- Common/DTS.Common.Import/XML/XMLParseDASList.cs
- Common/DTS.Common.Import/XML/XMLParseGroupTemplates.cs
- Common/DTS.Common.Import/XML/XMLParseCalibrations.cs
- Common/DTS.Common.Import/XML/XMLPre20ParseCalibrations.cs
- Common/DTS.Common.Import/XML/XMLParseGroups.cs
- Common/DTS.Common.Import/XML/XMLParseTestSetups.cs
generated_at: "2026-04-17T15:26:52.176871+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "75086f6da3a24b58"
---
# XML Import Parsers Documentation
## 1. Purpose
This module provides a collection of XML parsing classes for importing configuration data into the DTS system. Each parser handles a specific domain entity (sensors, calibrations, groups, test setups, hardware, etc.) and follows a strategy pattern via the `XMLParseBase` abstract class. The module supports versioned imports with migration logic for pre-2.0 data formats, ID normalization to avoid collisions with existing database records, and cancellation support for long-running operations. Parsers transform XML elements into domain objects and populate an `ImportObject` container for downstream processing.
---
## 2. Public Interface
### XMLParseBase (Abstract Base Class)
```csharp
public abstract class XMLParseBase : IParseVariant
{
public string FileName { get; set; }
public abstract void Parse(ref ImportObject importObject);
protected XMLParseBase(XmlElement root, double importedVersion, Func<bool> isCancelled = null, bool skipNormalizing = false)
}
```
**Behavior:** Base class for all XML parsers. Maintains static ID mapping dictionaries (`_dasIdMapping`, `_groupIdMapping`, `_sensorIdMapping`, `_channelIdMapping`) for cross-parser ID normalization. Provides protected helper methods `GetXmlElement()` and `IsCancelled()`. Initializes an internal `XmlWriter` for generating transformed XML.
---
### XMLParseDASList
```csharp
public XMLParseDASList(XmlElement root, double importedVersion, Func<bool> isCancelled = null, bool skipNormalizing = false)
public IImportNotification ImportNotification { get; set; }
public override void Parse(ref ImportObject importObject)
public List<DASHardware> ParseDASList(XmlElement root)
```
**Behavior:** Parses DAS (Data Acquisition System) hardware from XML. Normalizes DAS IDs starting at -2 (preserving -1 for unassigned channels per FB 13544). Validates hardware types against `DTS.Common.Enums.Hardware.HardwareTypes`. Clears `_dasIdMapping` on construction.
---
### XMLParseSensors
```csharp
public XMLParseSensors(XmlElement root, double importedVersion, Func<bool> isCancelled = null, bool skipNormalizing = false)
public IImportNotification ImportNotification { get; set; }
public override void Parse(ref ImportObject importObject)
public XmlElement ConvertSensors(IEnumerable<SensorData> sensors)
public IEnumerable<SensorData> ParseSensors(XmlElement root)
```
**Behavior:** Parses sensor data. Normalizes sensor `DatabaseId` starting at -2 (preserving -1 for invalid). Populates `_sensorIdMapping` during conversion. Respects `_skipNormalizing` flag.
---
### XMLParseGroups
```csharp
public XMLParseGroups(XmlElement root, double importedVersion, Func<bool> isCancelled = null)
public IImportNotification ImportNotification { get; set; }
public override void Parse(ref ImportObject importObject)
public List<IGroup> ParseGroups(XmlElement root, ref ImportObject importObject)
```
**Behavior:** Parses static groups. Clears `_groupIdMapping` on construction. Normalizes group IDs starting at -2. Maps group channels' DAS and Sensor IDs using `_dasIdMapping` and `_sensorIdMapping`. Handles deleted sensors gracefully (FB 14308) by setting `SensorId = 0`. Uses string-based group ID mapping for pre-2.1 exports, integer-based for 2.1+.
---
### XMLParseTestSetups
```csharp
public XMLParseTestSetups(XmlElement root, double importedVersion, Func<bool> isCancelled = null, bool skipNormalizing = false)
public IImportNotification ImportNotification { get; set; }
public override void Parse(ref ImportObject importObject)
public IEnumerable<TestTemplate> ParseTestTemplate(ImportObject importObject, XmlElement root)
```
**Behavior:** Parses test setups/templates. Clears `_channelIdMapping` on construction. Normalizes channel IDs and group IDs within test templates. Maps hardware references using `_dasIdMapping`. Sets `TestSetupImportFileFormat` on the import object. Catches and records XML read errors as warnings (FB 36879). Handles deleted sensors (FB 14308) and orphaned static group references.
---
### XMLParseCalibrations
```csharp
public XMLParseCalibrations(XmlElement root, double importedVersion, Func<bool> isCancelled = null)
public IImportNotification ImportNotification { get; set; }
public override void Parse(ref ImportObject importObject)
public XmlElement ConvertCalibrations(IEnumerable<SensorCalibration> calibrations)
public IEnumerable<SensorCalibration> ParseCalibrations(XmlElement root)
```
**Behavior:** Parses sensor calibrations. Version-specific handling: for version 1.0, sets `AtCapacity = false` and derives `SensitivityUnits` from `NonLinear`/`IsProportional` flags. Uses `FileUtils.DataPROPre20XmlVersion` threshold.
---
### XMLParseGroupTemplates
```csharp
public XMLParseGroupTemplates(XmlElement root, double importedVersion, ISO.ISO13499FileDb iSO13499FileDb, Func<bool> isCancelled = null)
public override void Parse(ref ImportObject importObject)
public IEnumerable<DataPROWin7.DataModel.TestObjectTemplate> ParseGroupTemplates(ref ImportObject importObject, XmlElement root)
```
**Behavior:** Parses group templates (test object templates). Requires `ISO13499FileDb` reference. Builds channel lookup from `importObject.CustomChannels()`. Sets `Embedded = true` for system-built or embedded templates. Throws `NotSupportedException` if referenced ISO test object is not found (FB 8790).
---
### XMLParseUsers
```csharp
public XMLParseUsers(XmlElement root, double importedVersion, IEnumerable<IUIItems> uiItems, Func<bool> isCancelled = null)
public IImportNotification ImportNotification { get; set; }
public override void Parse(ref ImportObject importObject)
```
**Behavior:** Parses user records. Requires `IEnumerable<IUIItems>` for user construction. Sets import status to `ReadingUsers`.
---
### XMLParseGlobalSettings
```csharp
public XMLParseGlobalSettings(XmlElement root, double importedVersion, Func<bool> isCancelled = null)
public IImportNotification ImportNotification { get; set; }
public override void Parse(ref ImportObject importObject)
```
**Behavior:** Parses global settings into a `Dictionary<string, string>`. Extracts `SettingName` and `SettingValue` child elements.
---
### XMLParseSensorModels
```csharp
public XMLParseSensorModels(XmlElement root, double importedVersion, Func<bool> isCancelled = null)
public override void Parse(ref ImportObject importObject)
```
**Behavior:** Parses `SensorModel` objects. Creates new instances and calls `ReadXML` on each child element.
---
### XMLParseCustomerDetails, XMLParseLabDetails, XMLParseTestEngineerDetails
```csharp
public XMLParseCustomerDetails(XmlElement root, double importedVersion, Func<bool> isCancelled = null)
public XMLParseLabDetails(XmlElement root, double importedVersion, Func<bool> isCancelled = null)
public XMLParseTestEngineerDetails(XmlElement root, double importedVersion, Func<bool> isCancelled = null)
public IImportNotification ImportNotification { get; set; } // All three
public override void Parse(ref ImportObject importObject) // All three
```
**Behavior:** Parse ISO entity details (customer, lab, test engineer). Each reads child elements, converts via internal `XmlWriter`, and re-parses. Sets specific import status (`ReadingCustomerDetails`, `ReadingLabDetails`).
---
### MME Custom Parsers (7 classes)
```csharp
// All follow same pattern:
public XMLParseMMECustom[Type](XmlElement root, double importedVersion, Func<bool> isCancelled = null)
public override void Parse(ref ImportObject importObject)
// Types: Directions, TestObjects, Positions, FineLoc3s, FineLoc2s, FineLoc1s, FilterClasses, Channels, MainLocations, PhysicalDimensions
```
**Behavior:** Each parses ISO MME reference data types by iterating child nodes and calling `ReadXML` on each `XmlElement`. Most check `IsCancelled()` per iteration; `XMLParseMMECustomChannels` does not.
---
### Pre-20 Migration Parsers
```csharp
// XMLPre20ParseGroupTemplates
public XMLPre20ParseGroupTemplates(XmlElement root, double importedVersion, XMLParseGroupTemplates xmlParseGroupTemplates, Func<bool> isCancelled = null)
// XMLPre20ParseSensors
public XMLPre20ParseSensors(XmlElement root, double importedVersion, XMLParseSensors xmlParseSensors, Func<bool> isCancelled = null)
public XmlElement MigrateSensors(IEnumerable<SensorData> sensors)
// XMLPre20ParseDASList
public XMLPre20ParseDASList(XmlElement root, double importedVersion, XMLParseDASList xmlParseDASList, Func<bool> isCancelled = null)
public List<DASHardware> ParsePre20DASList(XmlElement root)
// XMLPre20ParseCalibrations
public XMLPre20ParseCalibrations(XmlElement root, double importedVersion, XMLParseCalibrations xmlParseCalibrations, Func<bool> isCancelled = null)
```
**Behavior:** Decorator-style parsers that delegate to their non-Pre20 counterparts after performing version-specific migration. `XMLPre20ParseSensors` assigns negative database IDs starting at -1. `XMLPre20ParseDASList` wraps ISO hardware in `DASHardware` instances.
---
## 3. Invariants
1. **ID Normalization Range:** DAS, Sensor, Group, and Channel IDs are normalized to negative integers starting at -2 (or -1 for sensors in pre-20 migration), preserving -1 for "invalid/unassigned" semantics.
2. **Static Mapping Dictionaries:** `_dasIdMapping`, `_groupIdMapping`, `_sensorIdMapping`, and `_channelIdMapping` are `static readonly` and shared across all parser instances. Callers must ensure proper sequencing (DAS before Sensors before Groups before TestSetups).
3. **Group ID Mapping Key Type:** `_groupIdMapping` uses `string` keys to support both legacy name-based references (pre-2.1) and modern ID-based references (2.1+).
4. **Cancellation Contract:** If `isCancelled` parameter is null, `IsCancelled()` returns `false`. Parsers return partially-populated lists when cancelled mid-iteration.
5. **ImportObject Population:** All `Parse` methods modify the passed `ImportObject` via `ref` and call specific `Add*` methods (e.g., `AddSensors`, `AddHardwareList`, `AddStaticGroups`).
6. **Version Thresholds:**
- `FileUtils.DataPROPre20XmlVersion` distinguishes pre-2.0 from modern formats
- `FileUtils.DataPRO21XmlVersion` (2.1+) changes group ID reference semantics
- Version 1.0 has special calibration sensitivity unit handling
---
## 4. Dependencies
### This module depends on:
- `DTS.Common.Import.Interfaces` - `ImportObject`, `IParseVariant`, `IImportNotification`, `ImportStatus`, `ImportError`, `ImportSeverityError`
- `DTS.Common.Interface` - `IUIItems`, sensor interfaces
- `DTS.Common.Interface.Groups.GroupList` - `IGroup`, group interfaces
- `DTS.Common.Interface.GroupTemplate` - Group template interfaces
- `DTS.Common.SharedResource.Strings` - Localized error messages (`StringResources`)
- `DTS.Common.Enums.DBExport` - `TopLevelFields` enum for XML element names
- `DTS.Common.Enums` - Various enums
- `DTS.Common.Enums.Sensors` - `SensorConstants.SensUnits`
- `DTS.Common.Utils` - `FileUtils` with version constants
- `DTS.SensorDB` - `SensorData`, `SensorCalibration`, `SensorModel`
- `DTS.Slice.Users` - `User` class
- `DataPROWin7.DataModel` - `DASHardware`, `TestObjectTemplate`, `TestObject`
- `DTS.Common.Classes.TestSetups` - `TestTemplate`
- `DTS.Common.ISO` or `ISO` namespace - MME types (`MMEDirections`, `MMETestObjects`, `MMEPositions`, `MMEFineLocations1/2/3`, `MMEFilterClasses`, `MMEPossibleChannels`, `MMETransducerMainLocation`, `MMEPhysicalDimensions`, `CustomerDetails`, `TestEngineerDetails`, `LabratoryDetails`)
- `System.Xml` - `XmlElement`, `XmlDocument`, `XmlWriter`
### What depends on this module:
- Not explicitly shown in source, but inferred: Import orchestration code that instantiates these parsers based on XML structure and version, then processes the populated `ImportObject`.
---
## 5. Gotchas
1. **Static Dictionary State:** The ID mapping dictionaries are static and shared. `XMLParseDASList`, `XMLParseGroups`, and `XMLParseTestSetups` clear their respective dictionaries in constructors, but if parsers are instantiated out of order or reused, mappings may be incorrect.
2. **Missing Cancellation Check:** `XMLParseMMECustomChannels.ParseCustomChannels` does not check `IsCancelled()` during iteration, unlike all other MME parsers.
3. **Unused ImportNotification Property:** `XMLParseMMECustomChannels` declares `ImportNotification` property but never uses it.
4. **Empty Error Handling:** In `XMLParseDASList.ParseDASList`, invalid DAS entries are collected into `invalidDAS` list but the subsequent `if (invalidDAS.Any()) { //??? }` block is empty—no error is reported.
5. **Pre-20 Sensor ID Collision:** `XMLPre20ParseSensors.MigrateSensors` starts IDs at -1, while `XMLParseSensors.ConvertSensors` starts at -2. This inconsistency could cause issues if both are used in the same import pipeline.
6. **Group Template Embedded Logic:** `XMLParseGroupTemplates` sets `template.Embedded = template.SysBuilt || template.Embedded` after reading XML, which may override the imported value unexpectedly.
7. **Orphaned Static Group Handling:** `XMLParseTestSetups.ConvertTestTemplates` silently sets `group.StaticGroupId = null` if the ID isn't found in `_groupIdMapping`, with only a comment explaining this is for buggy old exports.
8. **Version 1.0 Calibration Assumptions:** The calibration parser makes assumptions about sensitivity units for version 1.0 files based on `NonLinear` and `IsProportional` flags that may not be accurate for all legacy data.
9. **XmlWriter State Management:** `XMLParseBase.GetXmlElement()` calls `_writer.Close()`, which means it can only be called once per instance. Subsequent calls would fail.