Files
2026-04-17 14:55:32 -04:00

131 lines
8.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
source_files:
- Common/DTS.Common.Serialization/Test/Module/IConvertable.cs
- Common/DTS.Common.Serialization/Test/Module/CalculatedChannel.cs
generated_at: "2026-04-16T03:40:25.931280+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "ac5cc711621ec54b"
---
# Module
## Documentation Page: `DTS.Serialization.Test.Module.IConvertable` and `DTS.Serialization.Test.Module.CalculatedChannel`
---
### 1. Purpose
This module provides serialization infrastructure and a concrete implementation for handling *calculated channels* in the DTS test data model. Specifically, the `IConvertable` interface defines a contract for objects that can be converted to/from the internal `Test.Module` serialization format, enabling interoperability with external or legacy serialization layers. The `CalculatedChannel` class implements this interface (via inheritance from `AnalogInputChannel`, which presumably implements `IConvertable`) and represents a derived channel whose values are computed from one or more source channels using a user-defined formula. It supports XML serialization/deserialization with custom attribute tagging and array-based source channel/module metadata.
---
### 2. Public Interface
#### `IConvertable` Interface (Nested in `Test.Module`)
- **`Module ToDtsSerializationTestModule(Test parentTest)`**
Converts the implementing object into a `Test.Module` instance. The `parentTest` parameter identifies the containing test context.
- **`void FromDtsSerializationTestModule(Module testModule, ReportErrors reportErrors)`**
Initializes the implementing object from a `Test.Module` instance. The `reportErrors` delegate is used to surface validation or parsing errors encountered during deserialization.
> **Note**: The interface is declared in `IConvertable.cs`, but its implementation is not shown in the provided source. The `CalculatedChannel` class inherits from `AnalogInputChannel`, which is assumed to implement `IConvertable`.
#### `CalculatedChannel` Class (Nested in `Test.Module`)
- **`CalculatedChannel(Module parentModule)`**
Constructor. Initializes a new `CalculatedChannel` instance with the given parent module.
- **`int[] SourceChannelNumber { get; set; }`**
Gets/sets the array of channel numbers from which this calculated channel derives its data.
- **`int[] SourceModuleNumber { get; set; }`**
Gets/sets the array of module numbers corresponding to each source channel.
- **`string[] SourceModuleSerialNumber { get; set; }`**
Gets/sets the array of serial numbers for the modules containing the source channels.
- **`string Calculation { get; set; }`**
Gets/sets the calculation expression (e.g., `"A + B * 2"`) applied to the source channels. Default: `"NONE"`.
- **`ulong T1 { get; set; }`**
Gets/sets a time parameter (likely for HIC calculations). Default: `0`.
- **`ulong T2 { get; set; }`**
Gets/sets a second time parameter (likely for HIC calculations). Default: `0`.
- **`double HIC { get; set; }`**
Gets/sets the Head Injury Criterion value (a derived metric). Default: `0.0`.
- **`double SampleRateHz { get; set; }`**
Gets/sets the sample rate (in Hz) for this calculated channel. Inherited from base class or set explicitly.
- **`override void WriteXml(XmlWriter writer)`**
Serializes the object to XML. Writes attributes for all public properties (including `SourceChannelNumber`, `SourceModuleNumber`, `SourceModuleSerialNumber`, `Calculation`, `SampleRateHz`, and conditionally `HIC`, `T1`, `T2`). Uses `AttributeExtractor<XmlSerializationTagAttribute>` to resolve XML tag names.
- **`override void ReadXml(XmlReader reader)`**
Deserializes the object from XML. Reads attributes using `PropertyAttributeDecoder<CalculatedChannel>`. Handles parsing of comma-separated integer arrays (`SourceChannelNumber`, `SourceModuleNumber`) and custom-delimited string arrays (`SourceModuleSerialNumber`, using `"_.-._"` as delimiter).
- **`static CalculatedChannel CreateInstance(Channel[] channels)`**
Factory method to create a `CalculatedChannel` from multiple source `Channel`s. Validates that the maximum sample rate is a multiple of each source channels sample rate. Copies all properties from the first channel using `TypeDescriptor`. Initializes `SourceChannelNumber`, `SourceModuleNumber`, and `SourceModuleSerialNumber` arrays from all input channels.
- **`static CalculatedChannel CreateInstance(Channel sourceChannel)`**
Factory method to create a `CalculatedChannel` from a single `Channel`. Sets `SourceChannelNumber`, `SourceModuleNumber`, and `SourceModuleSerialNumber` to single-element arrays derived from the source channel.
- **`override bool Equals(object obj)`**
Performs memberwise equality comparison with another `CalculatedChannel`. Compares: `ChannelId`, `SourceChannelNumber`, `ChannelDescriptionString`, `EngineeringUnits` (case-insensitive), `Calculation`, and `IsoCode`.
- **`override int GetHashCode()`**
Returns the hash code from the base class (no custom logic visible).
- **`override string ToString()`**
Returns `ChannelDescriptionString`.
---
### 3. Invariants
- **Array Length Consistency**: For `SourceChannelNumber`, `SourceModuleNumber`, and `SourceModuleSerialNumber`, all three arrays must have identical length. This is *enforced by convention* in `CreateInstance`, but not validated in `ReadXml`/`WriteXml`.
- **Sample Rate Compatibility**: In `CreateInstance(Channel[])`, the maximum sample rate among source channels must be an integer multiple of each source channels sample rate; otherwise, an `InvalidOperationException` is thrown.
- **Optional Fields**: `HIC`, `T1`, and `T2` are only serialized if `_HIC.IsValueInitialized` is `true`. This implies they are initialized conditionally (e.g., only when non-zero or explicitly set).
- **Default Values**: `Calculation` defaults to `"NONE"`, `SampleRateHz` defaults to `0`, numeric arrays default to `null`, and `HIC`/`T1`/`T2` default to `0`/`0U`/`0U`.
- **Serialization Format**:
- Integer arrays are comma-separated (e.g., `"1,2,3"`).
- String arrays use `"_.-._"` as a delimiter (e.g., `"SN1_.-._SN2_.-._SN3"`).
- XML attributes use tags defined by `[XmlSerializationTag(...)]` attributes.
---
### 4. Dependencies
#### Module Dependencies
- **`DTS.Common.Utilities.Xml.AttributeExtractor<T>`**
Used in `WriteXml` to extract XML tag names from attributes.
- **`DTS.Common.Utilities.Xml.PropertyAttributeDecoder<T>`**
Used in `ReadXml` to decode XML attributes into properties.
- **`DTS.Common.Utilities.Logging.APILogger`**
Used for logging in `WriteXml` and `ReadXml`.
- **`System.ComponentModel.TypeDescriptor`**
Used in `CreateInstance` to copy property values via reflection.
- **`DTS.Common.Classes.Sensors.LinearizationFormula`**
Used in `CreateInstance(Channel[])` to clone the linearization formula.
#### Inferred Dependencies
- `AnalogInputChannel` (base class of `CalculatedChannel`) must implement `IConvertable`, though its implementation is not shown here.
- `Test` and `Module` classes are nested containers (see namespace structure).
- `ReportErrors` delegate type is referenced in `IConvertable.FromDtsSerializationTestModule` but not defined in the provided source.
---
### 5. Gotchas
- **Array Delimiter Ambiguity**: The string array delimiter `"_.-._"` is not documented in comments and may conflict with legitimate serial numbers containing that substring. No escaping or quoting is applied.
- **Partial Initialization in `ReadXml`**: `HIC`, `T1`, and `T2` are only deserialized if the `HIC` attribute is present and non-whitespace. If only `T1`/`T2` are present, they will remain at default (`0`), potentially masking incomplete data.
- **Sample Rate Validation Only in Factory**: The sample rate divisibility check occurs *only* in `CreateInstance(Channel[])`, not during XML deserialization or direct property assignment. Invalid rates may be silently stored.
- **Property Copying via Reflection**: `CreateInstance` uses `TypeDescriptor.GetProperties` to copy properties. This may fail silently for properties that throw exceptions during `GetValue`/`SetValue` (exceptions are logged or swallowed).
- **No Deep Clone for `LinearizationFormula`**: The `LinearizationFormula` is cloned via constructor, but other reference-type properties (e.g., `LinearizationFormula` is the only one explicitly cloned) may be shared if not handled.
- **Case-Insensitive Comparison Only for `EngineeringUnits`**: The `Equals` method uses `StringComparison.OrdinalIgnoreCase` for `EngineeringUnits`, but other string properties (`Calculation`, `ChannelDescriptionString`, `IsoCode`) use case-sensitive comparison—this inconsistency may cause confusion.
- **`SourceModuleNumber` Not Populated in Factories**: In both `CreateInstance` overloads, `SourceModuleNumber` is initialized as an empty array (`moduleNumbers` is never populated), which is likely a bug.
> **Note**: The `ReportErrors` delegate signature and `AnalogInputChannel`s implementation of `IConvertable` are not visible in the provided source. Their behavior is inferred.