Files

123 lines
12 KiB
Markdown
Raw Permalink Normal View History

2026-04-17 14:55:32 -04:00
---
source_files:
- Common/DTS.Common/Classes/TestSetups/SimpleHardware.cs
- Common/DTS.Common/Classes/TestSetups/TestSetupHelper.cs
- Common/DTS.Common/Classes/TestSetups/ExtraProperties.cs
- Common/DTS.Common/Classes/TestSetups/ROIPeriodChannelRecord.cs
- Common/DTS.Common/Classes/TestSetups/TestSetupHardwareRecord.cs
- Common/DTS.Common/Classes/TestSetups/TestSetupROIsRecord.cs
- Common/DTS.Common/Classes/TestSetups/CalculatedChannelRecord.cs
- Common/DTS.Common/Classes/TestSetups/ISFFile.cs
- Common/DTS.Common/Classes/TestSetups/GraphRecord.cs
- Common/DTS.Common/Classes/TestSetups/RegionOfInterest.cs
- Common/DTS.Common/Classes/TestSetups/ISFSensorRecord.cs
generated_at: "2026-04-16T03:18:08.842826+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "9bc5c021742b55c0"
---
# TestSetups Module Documentation
## 1. Purpose
This module provides core data structures and helper utilities for representing and managing test setup configurations within the DTS system. It defines immutable and mutable record types that model database entities (e.g., hardware assignments, ROIs, calculated channels, graphs), along with supporting infrastructure for ISF file I/O and test setup naming. The module serves as the data layer abstraction for test setup management—enabling serialization/deserialization from database queries, file formats (ISF), and interoperation with UI and business logic layers through interfaces and property change notifications.
## 2. Public Interface
### Classes
#### `SimpleHardware`
- **Signature**: `public class SimpleHardware : Tuple<string, string, int, int>`
- **Behavior**: A lightweight, immutable tuple-based representation of hardware configuration. Exposes `SerialNumber`, `ParentDAS`, `DASId`, and `DASType` via named properties derived from tuple items. Used for passing hardware metadata without database persistence.
#### `TestSetupHelper`
- **Signature**: `public abstract class TestSetupHelper`
- **Behavior**: A static helper class for managing test setup names by ID. Provides `SetTestSetupName`, `GetTestSetupName`, and `ClearTestSetupNames` methods. Maintains an internal dictionary mapping integer IDs to string names.
#### `ExtraProperty`
- **Signature**: `[Serializable] public class ExtraProperty : IExtraProperty`
- **Behavior**: A mutable, INotifyPropertyChanged-enabled class representing a key-value pair for extra properties. Supports two constructors: parameterized (`key`, `value`) and copy constructor from `IExtraProperty`. Includes `PasteCommand` and `ItemStatus` properties (ignored during JSON serialization via `[ScriptIgnore]`).
#### `ROIPeriodChannelRecord`
- **Signature**: `public class ROIPeriodChannelRecord : BasePropertyChanged, IROIPeriodChannelRecord`
- **Behavior**: Represents a record from the `ROIPeriodChannels` database table. Properties: `TestSetupROIId`, `ChannelName`, `ChannelId`. Constructor accepts `IDataReader` and `storedProcedureVersionToUse`; `ChannelId` is set to `-1` if the DB version predates its introduction (`Constants.ROIPERIODCHANNELS_CHANNELID_DB_VERSION`).
#### `TestSetupHardwareRecord`
- **Signature**: `public class TestSetupHardwareRecord : Base.BasePropertyChanged, ITestSetupHardwareRecord`
- **Behavior**: Represents a record from the `TestSetupHardware` table. Properties: `DASId`, `TestSetupId`, `AddDAS`, `SamplesPerSecond`, `IsClockMaster`, `PTPDomainId`, `AntiAliasFilterRate`. Supports three constructors: default, `IDataReader` (with version-aware `PTPDomainId` parsing), and copy constructor from `ITestSetupHardwareRecord`.
#### `TestSetupROIsRecord`
- **Signature**: `public class TestSetupROIsRecord : BasePropertyChanged, ITestSetupROIRecord`
- **Behavior**: Represents a record from the `TestSetupROIs` table. Properties: `TestSetupROIId`, `TestSetupId`, `Suffix`, `ROIStart`, `ROIEnd`, `IsEnabled`, `IsDefault`. Constructor accepts `IDataReader`; note: `TestSetupId` is incorrectly assigned from `"TestSetupROIId"` column in constructor (see *Gotchas*).
#### `CalculatedChannelRecord`
- **Signature**: `public class CalculatedChannelRecord : BasePropertyChanged, ICalculatedChannelRecord`
- **Behavior**: Represents a calculated channel record. Properties include `Name`, `TestSetupName`, `Id`, `Operation`, `CalculatedValueCode`, `InputChannelIds` (string array), `CFCForInputChannels`, `ChannelFilterClassForOutput`, `TestSetupId`, `ViewInRealtime`, `ClipLength`. Supports default, copy (`ICalculatedChannelRecord`), and `IDataReader` constructors. Input channel IDs are parsed from CSV using `CultureInfo.InvariantCulture.TextInfo.ListSeparator`.
#### `ISFFile`
- **Signature**: `public class ISFFile`
- **Behavior**: Handles reading/writing ISF (Instrumentation Sensor Format) files. Contains fixed-length header fields (`TestSetupName`, `NumberOfRecords`, `TestType`, `TestDivision`, `TCFile`) and a list of `IISFSensorRecord` objects. Methods: `AddRecord`, `WriteToFile`, `AddSensors`. Header line parsing uses fixed offsets and padding with spaces.
#### `GraphRecord`
- **Signature**: `public class GraphRecord : BasePropertyChanged, IGraphRecord`
- **Behavior**: Represents a graph configuration record. Properties: `GraphId`, `TestSetupId`, `GraphName`, `GraphDescription`, `ChannelsString`, axis range flags (`UseDomainMin`, `UseDomainMax`, `UseRangeMin`, `UseRangeMax`) and their corresponding min/max values, `ThresholdsString`, `LocalOnly` (deprecated). Supports default, copy, and `IDataReader` constructors.
#### `RegionOfInterest`
- **Signature**: `[Serializable] public class RegionOfInterest : IRegionOfInterest`
- **Behavior**: A mutable, INotifyPropertyChanged-enabled class modeling a time-based ROI. Properties: `Suffix`, `Start`, `End`, `IsEnabled`, `IsDefault`, `ChannelNames`, `ChannelIds`. Includes validation to ensure `Start < End`. Notifies via `RegionOfInterestChangedEvent` (via Prism EventAggregator) on value changes, unless `Deserializing` is true. Provides utility methods for channel name formatting (`GetAnalogChanName`, `GetChanName`, `RemoveParentDASName`, `RemoveAssignedByIDFromHardwareString`) and silent assignment (`SetChannelNamesNoNotify`, `SetChannelIdsNoNotify`).
#### `ISFSensorRecord`
- **Signature**: `public class ISFSensorRecord : IISFSensorRecord`
- **Behavior**: Represents a single sensor record in an ISF file (comprising 4 fixed-length records of `RECORD_LENGTH` chars each). Exposes structured properties for sensor metadata (e.g., `DataChannelNumber`, `Tag`, `SerialNumber`, `Sensitivity`, `Capacity`, `EngineeringUnits`, `C1`, `C2`, `C3`, `EID`, `CommentPart1/2/3`, `SensorType`, `TOMConfigurationName`). Includes methods to set/get values and `Write` to `BinaryWriter`. Default constructor initializes `TOMConfigurationName` to `"STANDARD"`.
### Extension Methods (in `ISFFile`)
- `Fill<T>(this T[] sourceArray, T with)`: Fills entire array with value.
- `SubFill<T>(this T[] source, T with, int startIndex, int finalIndex)`: Fills from `startIndex` to `finalIndex` (exclusive), respecting array bounds.
- `SetValues<T>(this T[] source, T[] with, int startIndex, int length, T pad)`: Copies `with` array into `source` starting at `startIndex`, padding remaining space with `pad`.
- `GetValues<T>(this T[] source, int startIndex, int length)`: Returns a new array of `length` elements starting at `startIndex`.
## 3. Invariants
- **`SimpleHardware`**: Immutable after construction; tuple item mapping is fixed (`Item1→SerialNumber`, `Item2→ParentDAS`, `Item3→DASId`, `Item4→DASType`).
- **`TestSetupROIsRecord` constructor**: `TestSetupId` is incorrectly assigned from `"TestSetupROIId"` column (see *Gotchas*); no invariant violation is enforced by code.
- **`RegionOfInterest.Start` and `End`**: `Start < End` is enforced via setter logic (`Start` capped at `End - 0.01`, `End` capped at `Start + 0.01`). Infinity values are explicitly excluded from notifications (per comment referencing "FB 43462").
- **`ISFFile` header fields**: All fields are fixed-width and space-padded. `NumberOfRecords` is derived as `4 * number of sensor records`.
- **`ISFSensorRecord`**: Each record consists of exactly 4 fixed-length `char[]` arrays (`Record1``Record4`), each of length `ConstantsAndEnums.RECORD_LENGTH`.
- **`CalculatedChannelRecord.InputChannelIds`**: Stored as a string array; parsed from CSV using `ListSeparator` (e.g., comma in invariant culture).
- **`GraphRecord` axis flags**: `UseDomainMin/Max` and `UseRangeMin/Max` flags control whether corresponding min/max values are applied.
## 4. Dependencies
### Internal Dependencies
- **`DTS.Common.Base`**: Base classes (`BasePropertyChanged`) used by `ROIPeriodChannelRecord`, `TestSetupROIsRecord`, `CalculatedChannelRecord`, `GraphRecord`.
- **`DTS.Common.Interface.*`**: Interfaces implemented by record classes:
- `IROIPeriodChannelRecord`, `ITestSetupHardwareRecord`, `ITestSetupROIRecord`, `ICalculatedChannelRecord`, `IGraphRecord`, `IISFSensorRecord`, `IExtraProperty`, `IRegionOfInterest`.
- **`DTS.Common.Enums`**: `Operations` enum used by `CalculatedChannelRecord`.
- **`DTS.Common.Interface.Sensors`**: `ISensorData` used by `ISFSensorRecord.SetSensor`.
- **`DTS.Common.Events.RegionOfInterest`**: `RegionOfInterestChangedEvent` used by `RegionOfInterest`.
- **`Prism.*`**: `IEventAggregator`, `IContainerProvider`, `ContainerLocator` used by `RegionOfInterest.NotifyChanged`.
### External Dependencies
- **System.Data**: `IDataReader` for database record construction.
- **System.ComponentModel**: `INotifyPropertyChanged` via `PropertyChangedEventHandler`.
- **System.Web.Script.Serialization**: `[ScriptIgnore]` attribute.
- **System.Linq**: Used for array equality checks (`SequenceEqual`) and LINQ queries.
- **System**: Core types (`string`, `char[]`, `double`, `int`, `long`, `short`, `byte`, `bool`, `ICommand`).
### Inferred Usage
- **Database**: All record classes with `IDataReader` constructors imply usage with stored procedures (e.g., `sp_ROIPeriodChannelsGet`, `sp_TestSetupROIsGet`).
- **ISF I/O**: `ISFFile` and `ISFSensorRecord` are used for writing sensor data to ISF files.
- **UI**: `ExtraProperty`, `RegionOfInterest`, and record classes implement `INotifyPropertyChanged`, indicating use in data-bound UI layers (e.g., WPF).
## 5. Gotchas
- **`TestSetupROIsRecord` constructor bug**: `TestSetupId = Utility.GetInt(reader, "TestSetupROIId");` incorrectly reads from `"TestSetupROIId"` instead of `"TestSetupId"`. This will cause incorrect `TestSetupId` values when constructing from database reader.
- **`ISFSensorRecord.GetCapacity()`, `GetSensitivity()`, etc.**: Methods like `CapacityCharacters.ToString()` return the underlying `char[]`'s `ToString()` (i.e., type name), not the string content. Correct usage requires `new string(char[])` or `string.Concat(char[])`. This is likely a bug.
- **`RegionOfInterest.Suffix` validation**: Enforces that non-empty suffixes must start with `"_"` and be otherwise whitespace-free. If input violates this, it is auto-corrected (e.g., `"ROI1"``"_ROI1"`).
- **`RegionOfInterest.Deserializing` flag**: A static flag used to suppress change notifications during deserialization (e.g., to avoid triggering UI updates or event publishing during object construction). Requires careful coordination to avoid missed updates.
- **`ISFFile.NumberOfRecords` semantics**: `SetNumberOfRecords` sets `NumberOfRecords` to `4 * Records.Length`, implying each sensor record occupies 4 "records" in the ISF file (consistent with `ISFSensorRecord` having 4 `char[]` fields).
- **`CalculatedChannelRecord.InputChannelIds` copy constructor**: Uses `CopyTo` on `record.InputChannelIds` into `_inputChannelIds`, but `_inputChannelIds` is initialized to `new string[0]` *before* the copy, causing `ArgumentException` if `record.InputChannelIds.Length > 0`. Should initialize `_inputChannelIds` to `new string[record.InputChannelIds.Length]` first.
- **`ISFSensorRecord.TOMConfigurationName`**: Default value `"STANDARD"` is hardcoded; other values are not supported per comments.
- **`RegionOfInterest.GetAnalogChanName` logic**: Distinguishes `"TEST_SPECIFIC_ANALOG_SERIAL"` and `"VOLTAGE_INPUT"` DAS types for special channel name parsing. Relies on `SensorConstants` values (not shown in source).
- **`TestSetupHelper.TestSetupNames`**: Static dictionary is shared across all usages; `ClearTestSetupNames()` affects all callers. No thread-safety is evident.