init
This commit is contained in:
BIN
enriched-qwen3-coder-next/Common/DTS.Common.Serialization/.DS_Store
vendored
Normal file
BIN
enriched-qwen3-coder-next/Common/DTS.Common.Serialization/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -0,0 +1,116 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/Control/ReviewableAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/IntervalSec.cs
|
||||
generated_at: "2026-04-16T03:39:42.724755+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "b95e2bb79309f305"
|
||||
---
|
||||
|
||||
# Control
|
||||
|
||||
## Documentation: `DTS.Slice.Control` Namespace – ReviewableAttribute & IntervalSec
|
||||
|
||||
---
|
||||
|
||||
### 1. Purpose
|
||||
|
||||
This module provides foundational types for representing *reviewable* attributes (e.g., displayable metadata in a UI review tab) and *time intervals* (in seconds) within the DTS Slice Control domain. `ReviewableAttribute` serves as an abstract base for dynamically computing and exposing attribute values (e.g., channel status, configuration metadata) for review purposes, while `IntervalSec` encapsulates a time range with begin/end times and supports interoperability with a serialization-specific counterpart via implicit conversions.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
#### `ReviewableAttribute` (Abstract Class)
|
||||
|
||||
- **`ReviewableAttribute(string name, DetermineValueString calculateValue)`**
|
||||
Constructor. Initializes the attribute with a name and a delegate used to compute the value on demand. Throws `ReviewableAttribute.Exception` on failure.
|
||||
|
||||
- **`string Name { get; }`**
|
||||
Read-only property returning the attribute’s display name.
|
||||
|
||||
- **`string Value { get; }`**
|
||||
Read-only property that invokes the `CalculateValue` delegate to compute the current value. On exception during computation, logs the error and returns `"N/A"` (does *not* throw).
|
||||
|
||||
- **`delegate string DetermineValueString();`**
|
||||
Public delegate defining the signature for value-computation methods.
|
||||
|
||||
- **`private DetermineValueString CalculateValue { get; set; }`**
|
||||
Private property storing the delegate. Throws `ApplicationException` if accessed before initialization.
|
||||
|
||||
#### `IntervalSec` (Concrete Class)
|
||||
|
||||
- **`IntervalSec()`**
|
||||
Parameterless constructor. Leaves `Begin` and `End` uninitialized (default to `0.0` due to `Property<double>` initialization, but semantically "uninitialized" per comment).
|
||||
|
||||
- **`IntervalSec(double begin, double end)`**
|
||||
Constructor initializing `Begin` and `End` to specified values. Throws generic `Exception` on failure.
|
||||
|
||||
- **`double Begin { get; set; }`**
|
||||
Read/write property for the interval’s start time (seconds).
|
||||
|
||||
- **`double End { get; set; }`**
|
||||
Read/write property for the interval’s end time (seconds).
|
||||
|
||||
- **`public static implicit operator Serialization.Test.IntervalSec(IntervalSec thisInterval)`**
|
||||
Implicit conversion to `DTS.Serialization.Test.IntervalSec`, using current `Begin`/`End`.
|
||||
|
||||
- **`public static implicit operator IntervalSec(Serialization.Test.IntervalSec thatInterval)`**
|
||||
Implicit conversion *from* `DTS.Serialization.Test.IntervalSec`, constructing a new instance.
|
||||
|
||||
- **`public override bool Equals(object obj)`**
|
||||
Memberwise equality check against another `IntervalSec`. Returns `false` if `obj` is `null` or not `IntervalSec`.
|
||||
|
||||
- **`public override int GetHashCode()`**
|
||||
Returns base hash code (note: does *not* combine `Begin`/`End` explicitly—see *Gotchas*).
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
|
||||
- **`ReviewableAttribute`**
|
||||
- `Name` must be non-null (enforced by `Property<string>` constructor with `null` as default, but no explicit validation—*potential risk*).
|
||||
- `CalculateValue` must be assigned before `Value` is accessed; otherwise, `ApplicationException` is thrown.
|
||||
- `Value` computation *never* throws; exceptions are caught and logged, returning `"N/A"`.
|
||||
|
||||
- **`IntervalSec`**
|
||||
- No invariant enforces `Begin ≤ End`; invalid intervals (e.g., `Begin > End`) are permitted.
|
||||
- `Begin` and `End` default to `0.0` (via `Property<double>` initialization), but the parameterless constructor comment states they are "uninitialized"—this is a semantic mismatch.
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
|
||||
- **`DTS.Slice.Control.ReviewableAttribute`**
|
||||
- *Depends on*:
|
||||
- `DTS.Utilities` (for `APILogger`, `Exceptional`, `Property<T>`)
|
||||
- `DTS.Utilities.DotNetProgrammingConstructs` (for `Property<T>`)
|
||||
- *Used by*: Unknown from source—likely subclassed by domain-specific reviewable attributes (e.g., `ChannelAttribute`, `SystemStatusAttribute`).
|
||||
|
||||
- **`DTS.Slice.Control.IntervalSec`**
|
||||
- *Depends on*:
|
||||
- `DTS.Common.Utilities`
|
||||
- `DTS.Common.Utilities.DotNetProgrammingConstructs` (for `Property<double>`, `Exceptional`)
|
||||
- `DTS.Serialization.Test.IntervalSec` (for implicit conversions)
|
||||
- *Used by*: Likely in time-windowing or data-slicing logic (e.g., selecting data within a time range).
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
|
||||
- **`ReviewableAttribute`**
|
||||
- `CalculateValue` is a *private* property—subclasses cannot override or inspect it directly. Initialization must occur in the base constructor.
|
||||
- `Value` silently fails on computation error (`"N/A"`), which may mask bugs if not logged.
|
||||
- No validation on `name` parameter (e.g., null/empty); `Property<string>` allows `null`.
|
||||
|
||||
- **`IntervalSec`**
|
||||
- `GetHashCode()` does *not* incorporate `Begin`/`End`, violating the contract that equal objects must have equal hash codes. This will cause failures in hash-based collections (e.g., `HashSet`, `Dictionary`).
|
||||
- `Begin`/`End` default to `0.0` despite constructor comment implying "uninitialized" state—this may lead to false positives (e.g., interval `[0.0, 0.0]` treated as valid).
|
||||
- Implicit conversions assume `Serialization.Test.IntervalSec` has matching `Begin`/`End` properties; no validation on conversion.
|
||||
|
||||
- **Both**
|
||||
- Heavy use of `try`/`catch` blocks wrapping property accessors and constructors—suggests legacy error-handling pattern. Consider refactoring to reduce overhead.
|
||||
- Reliance on `Property<T>` wrapper (not shown) implies a custom property system; behavior (e.g., change notifications) is not documented here.
|
||||
|
||||
None identified beyond the above.
|
||||
@@ -0,0 +1,86 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/Control/DAS/IFilterable.cs
|
||||
- Common/DTS.Common.Serialization/Control/DAS/IFilter.cs
|
||||
generated_at: "2026-04-16T03:41:25.272025+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "d1bb42983adadb6c"
|
||||
---
|
||||
|
||||
# DAS
|
||||
|
||||
## Documentation: `IFilterable` and `IFilter` Interfaces
|
||||
|
||||
---
|
||||
|
||||
### 1. **Purpose**
|
||||
|
||||
This module defines core interfaces (`IFilterable` and `IFilter`) for managing and applying signal filters to channel data within the DTS Slice Control DAS (Data Acquisition System) framework. It enables consumers to query available filters, set a current filter, optionally cache filter results for performance, and retrieve filtered data in specified display units. The interfaces serve as abstractions for channel filtering logic—likely implemented by concrete classes representing physical or logical channel groups in the control system.
|
||||
|
||||
---
|
||||
|
||||
### 2. **Public Interface**
|
||||
|
||||
#### `IFilterable` Interface
|
||||
*Namespace:* `DTS.Slice.Control.DAS.Channel`
|
||||
|
||||
| Member | Signature | Description |
|
||||
|--------|-----------|-------------|
|
||||
| `UseFilterCaching` | `bool UseFilterCaching { get; set; }` | Enables or disables caching of previously computed filtered results. |
|
||||
| `AvailableFilters` | `List<IFilter> AvailableFilters { get; }` | Returns a list of filters that can be applied to this object. |
|
||||
| `CurrentFilter` | `IFilter CurrentFilter { get; set; }` | Gets or sets the filter currently applied to data requests. |
|
||||
| `GetDataFilteredBy` | `double[] GetDataFilteredBy(IFilter filter, Event.Module.Channel.DataDisplayUnits displayUnits)` | Returns filtered data for the specified `filter` and `displayUnits`. |
|
||||
|
||||
#### `IFilter` Interface
|
||||
*Namespace:* `DTS.Slice.Control.DAS.Channel`
|
||||
|
||||
| Member | Signature | Description |
|
||||
|--------|-----------|-------------|
|
||||
| `Name` | `string Name { get; }` | Returns a human-readable name/description of the filter. |
|
||||
| `IsCfc` | `bool IsCfc { get; }` | Indicates whether the filter represents a cardinal CFC (Cycle Count Filter) value. |
|
||||
| `Type` | `ChannelFilter Type { get; }` | Returns the filter’s type (e.g., low-pass, high-pass), represented by the `ChannelFilter` enum (not shown in source). |
|
||||
| `CutoffFrequencyHz` | `double CutoffFrequencyHz { get; }` | Returns the cutoff frequency (in Hz) used by the filter. |
|
||||
| `Apply` (1) | `double[] Apply(Event.Module.Channel input, Event.Module.Channel.DataDisplayUnits displayUnits, bool bUseLegacyTDCSofwareFilterAdjustment)` | Applies the filter to channel data, converting to `displayUnits`. The `bUseLegacyTDCSofwareFilterAdjustment` flag adjusts output one sample to the right for backward compatibility with legacy TDC software. |
|
||||
| `Apply` (2) | `double[] Apply(double[] data, double sampleRate, bool bUseLegacyTDCSoftwareFilterAdjustment)` | Applies the filter to raw numeric data (assumed to be in base units), given the `sampleRate`. Same legacy adjustment flag applies. |
|
||||
| `ToBaseString` | `string ToBaseString()` | Returns the base name of the filter (e.g., `"LowPass"`), without any decoration (e.g., no suffix like `" (10 Hz)"`). |
|
||||
|
||||
> **Note**: The `Apply` methods are overloaded: one accepts an `Event.Module.Channel` object (likely containing metadata and raw data), and the other accepts raw `double[]` data plus `sampleRate`.
|
||||
|
||||
---
|
||||
|
||||
### 3. **Invariants**
|
||||
|
||||
- `AvailableFilters` must be non-null and immutable in the sense that its contents should not change during the lifetime of the `IFilterable` instance (though the list itself may be recreated on each access).
|
||||
- `CurrentFilter` must be either `null` or one of the items in `AvailableFilters`.
|
||||
- `GetDataFilteredBy` must return data consistent with the specified `filter` and `displayUnits`, and must not mutate the underlying channel data.
|
||||
- `IsCfc` and `Type` must be consistent: if `IsCfc` is `true`, then `Type` likely corresponds to a CFC-specific `ChannelFilter` value (exact mapping not specified in source).
|
||||
- The `bUseLegacyTDCSofwareFilterAdjustment` parameter in `Apply` controls sample alignment: when `true`, output is shifted one sample to the right (i.e., delayed by one sample period) to preserve legacy behavior.
|
||||
|
||||
---
|
||||
|
||||
### 4. **Dependencies**
|
||||
|
||||
#### Dependencies *of* this module:
|
||||
- `System.Collections.Generic` (`List<T>`)
|
||||
- `DTS.Common.Utilities` (namespace referenced, but no types used directly in interface definitions)
|
||||
- `Event.Module.Channel` (used in `Apply` signatures; type not shown, but assumed to contain raw channel data and metadata)
|
||||
- `Event.Module.Channel.DataDisplayUnits` (enum or type defining unit conversion options; not shown)
|
||||
|
||||
#### Dependencies *on* this module:
|
||||
- Any class implementing `IFilterable` (e.g., channel or group implementations) must provide filtering capabilities.
|
||||
- Any class implementing `IFilter` must define concrete filtering logic (e.g., `LowPassFilter`, `HighPassFilter`, `CfcFilter`).
|
||||
- Likely used by higher-level components in `DTS.Slice.Control.DAS` or `DTS.Slice.Control.CAS` namespaces (inferred from commented-out base interface in `IFilterable`).
|
||||
|
||||
---
|
||||
|
||||
### 5. **Gotchas**
|
||||
|
||||
- **Typo in parameter name**: In `GetDataFilteredBy`, the parameter `filter` is documented as `DTS.Slice.Control.CAS.Channel.IFilter`, but the actual interface is `DTS.Slice.Control.DAS.Channel.IFilter`. This may indicate outdated documentation or namespace refactoring.
|
||||
- **Typo in flag name**: `bUseLegacyTDCSofwareFilterAdjustment` is misspelled as `Sofware` (missing 't') in one `Apply` signature (`Apply` overload 1), but correctly spelled as `TDCSoftware` in the second overload. This inconsistency may cause confusion or errors in code generation or reflection-based usage.
|
||||
- **No explicit thread-safety guarantees**: Neither interface documents thread-safety; concurrent access to `CurrentFilter`, `UseFilterCaching`, or `Apply` may require external synchronization.
|
||||
- **Caching behavior unspecified**: While `UseFilterCaching` toggles caching, the caching strategy (e.g., cache key, eviction policy, scope) is not defined here—implementation-specific.
|
||||
- **`ToBaseString()` vs `ToString()`**: The comment implies `ToString()` is overridden elsewhere (likely in concrete implementations) to include metadata (e.g., `"LowPass (10 Hz)"`), while `ToBaseString()` returns the base name only. Consumers must be aware of this distinction when displaying filter names.
|
||||
|
||||
> **None identified from source alone.**
|
||||
> *(Note: The above gotchas are inferred from inconsistencies in naming and documentation; no behavioral quirks beyond those are evident from the interfaces themselves.)*
|
||||
@@ -0,0 +1,230 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/Control/Event/DasModuleAccessor.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/DasChannelAccessor.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/ChannelAccessor.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/ModuleChannelAccessor.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/DasModuleChannelAccessor.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/TestInformation.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Event.cs
|
||||
generated_at: "2026-04-16T03:41:53.208866+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "e1ba9340d986b9b2"
|
||||
---
|
||||
|
||||
# Documentation: `DTS.Slice.Control.Event` Accessor Classes and Related Types
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides accessor objects and supporting infrastructure for navigating and manipulating event data within the DTS Slice Control system. Specifically, it defines hierarchical dictionary-based accessors (`DasModuleAccessor`, `DasChannelAccessor`, `DasModuleChannelAccessor`, `ChannelAccessor`, `ModuleChannelAccessor`) that enable lookup of modules and channels by DAS ID, module number, and channel number combinations. It also includes the core `Event` class (a partial class with multiple files), which serves as the in-memory representation of a DAS event—encapsulating test metadata, modules, channels, and derived properties such as validation flags and serialization support. The module bridges low-level DAS serialization data (e.g., `DTS.Serialization.Test`) and higher-level control logic by offering structured, type-safe access to event components.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
All accessor classes and the `Event` class reside in the `DTS.Slice.Control` namespace and are declared as `public partial class Event`.
|
||||
|
||||
### `Event` Class
|
||||
|
||||
- **`Event()`**
|
||||
Default constructor. Initializes all properties to their default values.
|
||||
|
||||
- **`Event(string id, string description)`**
|
||||
Initializes an `Event` with the given `id` and `description`. Throws a wrapped exception on failure.
|
||||
|
||||
- **`Event(Test test, Test.ReportErrors reportErrors)`**
|
||||
Initializes an `Event` by converting from a `DTS.Serialization.Test` object via `FromDtsSerializationTest`. Rethrows exceptions directly.
|
||||
|
||||
- **`Event(string id, string description, List<Module> modules)`**
|
||||
Initializes an `Event` with `id`, `description`, and a list of `Module`s.
|
||||
|
||||
- **`Event(List<IDASCommunication> dases, EventInfoAggregate info)`**
|
||||
Initializes an `Event` by aggregating configuration and channel data from a list of DAS devices (`IDASCommunication`) and `EventInfoAggregate`. Populates `Modules`, `DasModules`, `DasChannels`, and `DasModuleChannels`. Throws `UserException` for missing DAS info or configuration. Validates test ID consistency across DAS units.
|
||||
|
||||
- **`string Id { get; set; }`**
|
||||
Gets/sets the event’s test ID.
|
||||
|
||||
- **`string Description { get; set; }`**
|
||||
Gets/sets the event’s description.
|
||||
|
||||
- **`Guid Guid { get; set; }`**
|
||||
Gets/sets the globally unique identifier for the event. Default is `Guid.Empty`.
|
||||
|
||||
- **`UInt16 FaultFlags { get; set; }`**
|
||||
Gets/sets the global fault flags for the event.
|
||||
|
||||
- **`DateTime InceptionDate { get; private set; }`**
|
||||
Gets the creation date of the event (set during construction). Defaults to `DateTime.Now`.
|
||||
|
||||
- **`List<Module> Modules { get; set; }`**
|
||||
Gets/sets the list of `Module` objects associated with this event.
|
||||
|
||||
- **`List<Module.Channel> CalculatedChannels { get; set; }`**
|
||||
Gets/sets the list of calculated channels.
|
||||
|
||||
- **`DasModuleAccessor DasModules { get; private set; }`**
|
||||
Returns a `DasModuleAccessor` keyed by DAS ID (`Common.DAS.Concepts.DAS.Id`), mapping to a `List<Module>`.
|
||||
|
||||
- **`DasChannelAccessor DasChannels { get; private set; }`**
|
||||
Returns a `DasChannelAccessor` keyed by DAS ID, mapping to a `List<Module.Channel>`.
|
||||
|
||||
- **`DasModuleChannelAccessor DasModuleChannels { get; private set; }`**
|
||||
Returns a `DasModuleChannelAccessor` keyed by DAS ID, mapping to a `ModuleChannelAccessor`.
|
||||
|
||||
- **`int LastAbsoluteChannelNumberInEvent { get; }`**
|
||||
Returns the highest absolute channel number across all modules and channels.
|
||||
|
||||
- **`bool IsTooLargeFor32BitVisualization { get; }`**
|
||||
Returns `true` if the total data volume (based on `TooLargeFor32BitVisualizationBytesPerSampleThreshold`) exceeds 2GB (0x7FFFFFFF bytes).
|
||||
|
||||
- **`double TooLargeFor32BitVisualizationBytesPerSampleThreshold { get; private set; }`**
|
||||
Threshold in bytes per sample used for 32-bit visualization size checks. Default: `2.0`.
|
||||
|
||||
- **`bool ContainsChannelsActiveInvalidZeroingWindows { get; }`**
|
||||
Returns `true` if any channel has `ZeroMethod == AverageOverTime` and an invalid averaging window.
|
||||
|
||||
- **`List<Module.Channel> ChannelsWithActiveInvalidZeroingWindows { get; }`**
|
||||
Returns the list of channels with active but invalid zeroing windows (e.g., window outside data range or negative indices).
|
||||
|
||||
- **`static string BaseSerializationDirectory { get; set; }`**
|
||||
Gets/sets the base directory path for event serialization.
|
||||
|
||||
- **`static string GetEventSerializationDirectory(string eventId)`**
|
||||
Returns the full path for the serialization directory of the given `eventId`.
|
||||
|
||||
- **`bool Equals(object obj)`**
|
||||
Overrides `Equals` to compare `Id`, `Description`, `Guid`, `Modules`, and `FaultFlags`.
|
||||
|
||||
- **`int GetHashCode()`**
|
||||
Overrides `GetHashCode`.
|
||||
|
||||
- **`Test ToDtsSerializationTest()`**
|
||||
Converts this `Event` to a `DTS.Serialization.Test`. Removes unconfigured/dummy channels before serialization.
|
||||
|
||||
- **`void FromDtsSerializationTest(Test that, Test.ReportErrors reportErrors)`**
|
||||
Populates this `Event` from a `DTS.Serialization.Test`. Re-throws `InvalidDataException` directly; wraps others.
|
||||
|
||||
- **`static implicit operator Test(Event sliceControlEvent)`**
|
||||
Implicit conversion operator to `DTS.Serialization.Test`.
|
||||
|
||||
- **`static bool IsG5(IDASCommunication idas)`**
|
||||
Returns `true` if the DAS serial number starts with `"5M"`.
|
||||
|
||||
- **`static bool IsSlice6DBModule(Module module)`**
|
||||
Returns `true` if `module.Description.ToLower() == "slice6db module"`.
|
||||
|
||||
### Accessor Classes
|
||||
|
||||
- **`DasModuleAccessor : ExceptionalDictionary<Common.DAS.Concepts.DAS.Id, List<Module>>`**
|
||||
Keyed by DAS ID, maps to list of `Module`s. Used to retrieve modules by DAS.
|
||||
|
||||
- **`DasChannelAccessor : ExceptionalDictionary<Common.DAS.Concepts.DAS.Id, List<Module.Channel>>`**
|
||||
Keyed by DAS ID, maps to list of `Module.Channel`s. Used to retrieve channels by DAS.
|
||||
|
||||
- **`DasModuleChannelAccessor : ExceptionalDictionary<Common.DAS.Concepts.DAS.Id, ModuleChannelAccessor>`**
|
||||
Keyed by DAS ID, maps to a `ModuleChannelAccessor`. Enables 3-level lookup: DAS ID → module index → channel index.
|
||||
|
||||
- **`ChannelAccessor : ExceptionalDictionary<int, Module.Channel>`**
|
||||
Keyed by `int` (module channel number), maps to a `Module.Channel`. Used as the innermost accessor.
|
||||
|
||||
- **`ModuleChannelAccessor : ExceptionalDictionary<int, ChannelAccessor>`**
|
||||
Keyed by `int` (module array index), maps to a `ChannelAccessor`. Enables lookup of channels by module number.
|
||||
|
||||
- **`TestInformation : Exceptional`** *(private)*
|
||||
Holds test metadata (`Id`, `Description`) per DAS. Used internally during event construction.
|
||||
|
||||
### Helper Methods (in `Event`)
|
||||
|
||||
- **`bool IsDummyChannel(Module.Channel channel)`**
|
||||
Returns `true` if `channel.ChannelDescriptionString.ToLower() == "dummy arm channel"`.
|
||||
|
||||
- **`bool IsTom(DASModule module)`**
|
||||
Returns `true` if module is a TOM (based on serial number or channel type).
|
||||
|
||||
- **`void PurgeUnconfiguredChannels()`**
|
||||
Removes unconfigured or dummy channels from all modules.
|
||||
|
||||
- **`bool IsEmptyModule(Module module)`**
|
||||
Returns `true` if module has no configured/non-dummy channels.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **`DasModules`, `DasChannels`, `DasModuleChannels` are always initialized**
|
||||
These properties are initialized in the `Property<T>` declaration with new accessor instances and are marked `readonly`/`true` (immutable reference after construction).
|
||||
|
||||
- **Module array indices must match list positions**
|
||||
The constructor for `Event(List<IDASCommunication>, EventInfoAggregate)` asserts:
|
||||
`Debug.Assert(DasModules[das.SerialNumber].Count - 1 == dasModule.ModuleArrayIndex);`
|
||||
This implies modules are inserted in order, and empty slots are filled with placeholder `Module` instances.
|
||||
|
||||
- **Test ID must be consistent across all DAS units**
|
||||
During construction, if any DAS reports a different `TestID`, an exception is thrown.
|
||||
|
||||
- **Channel absolute numbers are assigned sequentially**
|
||||
`absoluteChannelNumber` is incremented per channel added, and `Module.Channel.AbsoluteNumber` is set during `Channel.CreateChannel`.
|
||||
|
||||
- **`InceptionDate` is set once at construction**
|
||||
The setter is `private`, and the property is initialized with `DateTime.Now` or the serialization date.
|
||||
|
||||
- **`TooLargeFor32BitVisualizationBytesPerSampleThreshold` is immutable after construction**
|
||||
Marked `readonly` and `true` in `Property<T>`.
|
||||
|
||||
- **`IsSlice6DBModule` check is case-insensitive**
|
||||
Compares `module.Description.ToLower()` to `"slice6db module"`.
|
||||
|
||||
- **`InvalidWindowAverage` is `short.MinValue`**
|
||||
Used to detect uninitialized or invalid window averages in zeroing logic.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Internal Dependencies (within this module)
|
||||
- `DTS.Slice.Control.Event.Module` and nested types (`Module.Channel`, `Module.AnalogInputChannel`, etc.)
|
||||
- `DTS.Common.Utilities.ExceptionalDictionary<TKey, TValue>`
|
||||
- `DTS.Common.Utilities.DotNetProgrammingConstructs.Property<T>`
|
||||
- `DTS.Slice.Control.Event.TestInformation` (private helper)
|
||||
|
||||
### External Dependencies
|
||||
- `DTS.Serialization.Test` (from `DTS.Serialization` namespace)
|
||||
- `DTS.DASLib.Service.IDASCommunication`, `DASModule`, `DASChannel`, `EthernetTDAS`
|
||||
- `DTS.Common.Utilities.Logging.APILogger`
|
||||
- `System.Collections.Generic.List<T>`, `System.Guid`, `System.DateTime`, `System.Diagnostics.Debug`
|
||||
- `DTS.Serialization.StringResources.Strings` (for error messages)
|
||||
|
||||
### Inferred Usage
|
||||
- `EventInfoAggregate` is required for `Event(List<IDASCommunication>, EventInfoAggregate)` constructor.
|
||||
- `Test.ReportErrors` delegate is used in `FromDtsSerializationTest`.
|
||||
- Serialization infrastructure (`DTS.Serialization`) is used for round-trip conversion (`ToDtsSerializationTest`, `FromDtsSerializationTest`).
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **`DasModuleChannels` property key is `"DTS.Slice.Control.Event.DasModules"` (typo)**
|
||||
In the `Event` constructor, the `Property<DasModuleChannelAccessor>` for `DasModuleChannels` is initialized with the key `"DTS.Slice.Control.Event.DasModules"` instead of `"DTS.Slice.Control.Event.DasModuleChannels"`. This is likely a copy-paste bug.
|
||||
|
||||
- **`DasModuleChannelAccessor` uses `int` keys for module/channel indices, not typed IDs**
|
||||
Both `ModuleChannelAccessor` and `ChannelAccessor` use `int` keys (for module number and channel number, respectively), not strongly-typed IDs (see `xxx` comments in source). This risks confusion or errors if indices are misaligned.
|
||||
|
||||
- **`InceptionDate` defaults to `DateTime.Now`**
|
||||
If constructed via the default constructor, `InceptionDate` reflects the current time—not the serialization time. Only the `Event(Test, ...)` constructor sets it from the `Test.InceptionDate`.
|
||||
|
||||
- **`IsSlice6DBModule` is case-sensitive on `"slice6db module"`**
|
||||
Uses `ToLower()` for comparison, but the literal string is lowercase. If the source description varies in casing (e.g., `"Slice6DB Module"`), it may not match.
|
||||
|
||||
- **Zeroing window validation is complex and fragile**
|
||||
`ChannelsWithActiveInvalidZeroingWindows` performs multiple checks (negative indices, window outside data range). Edge cases (e.g., empty `TriggerSampleNumbers`, zero sample rate) are not explicitly handled beyond defaulting to `0`.
|
||||
|
||||
- **`PurgeUnconfiguredChannels` modifies `Modules` in-place**
|
||||
Called during `ToDtsSerializationTest`, this permanently removes channels. If the `Event` object is reused, data may be lost.
|
||||
|
||||
- **`IsDummyChannel` and `IsSlice6DBModule` use string comparisons**
|
||||
Relies on literal string matching (`"dummy arm channel"`, `"slice6db module"`). No constants or enums are defined for these.
|
||||
|
||||
- **`IsG5` checks only serial number prefix**
|
||||
Assumes `"5M"` prefix is sufficient to identify G5 devices. May be brittle if serial number formats change.
|
||||
|
||||
- **No thread safety**
|
||||
Comments in `Event.cs` explicitly note: *"Also need to add thread protection."* and *"Can we set locks in the property accessors..."* — no synchronization is present.
|
||||
|
||||
- **`TestInformation` is private and not exposed**
|
||||
While used internally, it is not part of the public API. Its properties (`Id`, `Description`) are not validated beyond assignment.
|
||||
|
||||
- **`TooLargeFor32BitVisualizationBytesPerSampleThreshold` is hardcoded to `2.0`**
|
||||
The justification in comments is detailed, but the value is not configurable at runtime (only via reflection or subclassing).
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/ReviewableDasSerialNumberAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/ReviewableAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/ReviewableSampleRateAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/Module.cs
|
||||
generated_at: "2026-04-16T03:41:50.953091+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "ac685bc8f1311025"
|
||||
---
|
||||
|
||||
# Documentation: `DTS.Slice.Control.Event.Module.ReviewableAttribute` and Related Classes
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides a framework for defining *reviewable attributes*—read-only, human-readable metadata properties attached to a specific `Event.Module` instance—that can be used during test review or reporting workflows. Specifically, it defines an abstract base class `ReviewableAttribute` and several concrete subclasses (e.g., `ReviewableDasSerialNumberAttribute`, `ReviewableSampleRateAttribute`, `ReviewableHardwareFrequencyAttribute`, `ReviewableTestDescriptionAttribute`) that expose module-level data (such as DAS serial number, sample rate, hardware anti-aliasing filter rate, and test description) in a standardized, reviewable format. These attributes are intended to be consumed by downstream review UIs or export tools that need to display or validate module-level metadata.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### `ReviewableAttribute` (Abstract Base Class)
|
||||
|
||||
- **Namespace**: `DTS.Slice.Control.Event.Module`
|
||||
- **Inherits from**: `Slice.Control.ReviewableAttribute` (external type, not shown in provided sources)
|
||||
- **Purpose**: Base class for all reviewable attributes attached to a `Module`.
|
||||
|
||||
#### Constructors
|
||||
|
||||
- `protected ReviewableAttribute(string name, DetermineValueString calculateValue)`
|
||||
- **Parameters**:
|
||||
- `name`: `string` – The display name of the attribute.
|
||||
- `calculateValue`: `DetermineValueString` – A delegate (function pointer) that returns the attribute’s value as a `string`.
|
||||
- **Behavior**: Initializes the base class with the provided name and value calculation delegate. This is the *only* constructor intended for use by subclasses.
|
||||
|
||||
- `public ReviewableAttribute(Event.Module module)` *(non-functional)*
|
||||
- **Behavior**: Throws a `NotImplementedException` wrapped in a `Module.ReviewableAttribute.Exception`. This constructor exists only to enforce that subclasses must use the parameterized constructor.
|
||||
|
||||
#### Nested Exception Type
|
||||
|
||||
- `public class Exception : Exception`
|
||||
- **Purpose**: Custom exception type used internally by `ReviewableAttribute` for constructor failures.
|
||||
|
||||
---
|
||||
|
||||
### `ReviewableDasSerialNumberAttribute`
|
||||
|
||||
- **Namespace**: `DTS.Slice.Control.Event.Module`
|
||||
- **Inherits from**: `ReviewableAttribute`
|
||||
- **Purpose**: Exposes the DAS serial number of the parent `Module`.
|
||||
|
||||
#### Constructor
|
||||
|
||||
- `public ReviewableDasSerialNumberAttribute(Event.Module module)`
|
||||
- **Parameters**:
|
||||
- `module`: `Event.Module` – The module to which this attribute is attached.
|
||||
- **Behavior**: Calls the base constructor with:
|
||||
- `name = "DAS Serial Number"`
|
||||
- `calculateValue = () => module.DasSerialNumber`
|
||||
- **Result**: The attribute’s value is the string value of `module.DasSerialNumber`.
|
||||
|
||||
---
|
||||
|
||||
### `ReviewableSampleRateAttribute`
|
||||
|
||||
- **Namespace**: `DTS.Slice.Control.Event.Module`
|
||||
- **Inherits from**: `ReviewableAttribute`
|
||||
- **Purpose**: Exposes the sample rate of the module, formatted with thousand separators.
|
||||
|
||||
#### Constructor
|
||||
|
||||
- `public ReviewableSampleRateAttribute(Event.Module module)`
|
||||
- **Parameters**:
|
||||
- `module`: `Event.Module`
|
||||
- **Behavior**: Calls base constructor with:
|
||||
- `name = "Sample Rate"`
|
||||
- `calculateValue = () => module.SampleRateHz.ToString("N")`
|
||||
- **Result**: The attribute’s value is `module.SampleRateHz.ToString("N")` (e.g., `"10,000.00"`).
|
||||
|
||||
---
|
||||
|
||||
### `ReviewableTestDescriptionAttribute`
|
||||
|
||||
- **Namespace**: `DTS.Slice.Control.Event.Module`
|
||||
- **Inherits from**: `ReviewableAttribute`
|
||||
- **Purpose**: Exposes the description of the *parent event* (not the module itself).
|
||||
|
||||
#### Constructor
|
||||
|
||||
- `public ReviewableTestDescriptionAttribute(Event.Module module)`
|
||||
- **Parameters**:
|
||||
- `module`: `Event.Module`
|
||||
- **Behavior**: Calls base constructor with:
|
||||
- `name = "Test Description"`
|
||||
- `calculateValue = () => module.ParentEvent.Description`
|
||||
- **Result**: The attribute’s value is `module.ParentEvent.Description`.
|
||||
|
||||
---
|
||||
|
||||
### `ReviewableHardwareFrequencyAttribute`
|
||||
|
||||
- **Namespace**: `DTS.Slice.Control.Event.Module`
|
||||
- **Inherits from**: `ReviewableAttribute`
|
||||
- **Purpose**: Exposes the hardware anti-aliasing filter rate, formatted to two decimal places.
|
||||
|
||||
#### Constructor
|
||||
|
||||
- `public ReviewableHardwareFrequencyAttribute(Event.Module module)`
|
||||
- **Parameters**:
|
||||
- `module`: `Event.Module`
|
||||
- **Behavior**: Calls base constructor with:
|
||||
- `name = "HW AAF"`
|
||||
- `calculateValue = () => module.AaFilterRateHz.ToString("N2")`
|
||||
- **Result**: The attribute’s value is `module.AaFilterRateHz.ToString("N2")` (e.g., `"5,000.00"`).
|
||||
|
||||
---
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **Attribute Name Consistency**: Each subclass hardcodes its `name` in the base constructor call. The names used are:
|
||||
- `"DAS Serial Number"`
|
||||
- `"Sample Rate"`
|
||||
- `"Test Description"`
|
||||
- `"HW AAF"`
|
||||
- **Value Calculation Must Not Be Null**: The `calculateValue` delegate passed to the base constructor must return a non-null `string`. If `module.DasSerialNumber`, `module.SampleRateHz`, etc., are `null` or `0`, the `ToString()` call may produce `"0"` or empty string, but no validation is performed.
|
||||
- **Parent Module Must Be Non-null**: The `module` parameter passed to any subclass constructor must be non-null; otherwise, dereferencing `module.DasSerialNumber`, `module.SampleRateHz`, etc., will throw `NullReferenceException`.
|
||||
- **No Runtime Validation**: There is no validation in the constructors or elsewhere to ensure the attribute name or value format conforms to any external schema—only formatting is applied via `ToString()`.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Dependencies *of* this module:
|
||||
|
||||
- **`DTS.Slice.Control.Event.Module`** (`Module.cs`): Provides the `Module` class whose properties (`DasSerialNumber`, `SampleRateHz`, `AaFilterRateHz`, `ParentEvent.Description`) are accessed by the attribute subclasses.
|
||||
- **`DTS.Slice.Control.ReviewableAttribute`** (external): Base class for `ReviewableAttribute`. Its `DetermineValueString` delegate type is assumed to be defined there.
|
||||
- **`DTS.Utilities`**: Used only for logging (not directly used in these files, but imported).
|
||||
- **`System`**: Standard .NET types (`string`, `delegate`, `Exception`, etc.).
|
||||
|
||||
### Dependencies *on* this module:
|
||||
|
||||
- **Unknown from source alone**: No direct callers are visible in the provided files. However, the naming and structure suggest this is used by a review/reporting subsystem (e.g., UI or export tool) that instantiates these attributes and calls into the base `ReviewableAttribute` API (e.g., to retrieve `Name` and `Value`).
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **Misleading XML Comments**: `ReviewableSampleRateAttribute` and `ReviewableHardwareFrequencyAttribute` are documented as “A reviewable filter frequency attribute attached to a specific channel.” — but they are attached to a `Module`, not a `Channel`. This is likely copy-paste error in comments.
|
||||
- **`ReviewableTestDescriptionAttribute` accesses `ParentEvent.Description`**, not `module.Description`. This may be intentional (e.g., to avoid duplication if description is event-level), but it’s non-obvious and could cause confusion.
|
||||
- **`ReviewableAttribute` constructor with `module` parameter is non-functional**: The constructor throws `NotImplementedException`. Subclasses *must* use the `protected` constructor with `name` and `calculateValue`. This is a safeguard, but could mislead developers into thinking the single-parameter constructor is usable.
|
||||
- **No `ToString()` formatting validation**: If `module.SampleRateHz` or `module.AaFilterRateHz` is `NaN` or `Infinity`, `ToString("N")` or `ToString("N2")` may produce `"NaN"`, `"Infinity"`, or `"–Infinity"`—which may not be desired for review displays.
|
||||
- **`StartRecordTimestampNanoSec` bug in `FromDtsSerializationTestModule`**: In `Module.cs`, line `TriggerTimestampNanoSec = that.StartRecordTimestampNanoSec;` appears to be a typo (should be `that.TriggerTimestampNanoSec`). While not directly in this module, it suggests potential data inconsistency risk in related code.
|
||||
- **No `Equals`/`GetHashCode` override in `ReviewableAttribute` subclasses**: Since these are likely used as keys or in collections, lack of value-based equality may cause subtle bugs. However, this is not evident from the source alone—no usage patterns are shown.
|
||||
|
||||
> **Note**: No usage of `ReviewableAttribute` beyond construction is visible in the provided files. The actual mechanism for invoking `calculateValue` (e.g., via a public `Value` property inherited from `Slice.Control.ReviewableAttribute`) is not documented here and must be assumed from the base class.
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/AnalogInputChannel/ReviewableShuntDeflectionAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/AnalogInputChannel/ReviewableFilterFrequencyAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/AnalogInputChannel/ReviewableIsoCodeAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/AnalogInputChannel/ReviewableDescriptionAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/AnalogInputChannel/ReviewableSerialNumberAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/AnalogInputChannel/ReviewableUnitsAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/AnalogInputChannel/ReviewableMinMaxEuAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/AnalogInputChannel/ReviewableCfcAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/AnalogInputChannel/ReviewableTargetShuntDeflectionAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/AnalogInputChannel/ReviewableMeasuredShuntDeflectionAttribute.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/AnalogInputChannel/ReviewableShuntDeflectionPercentageAttribute.cs
|
||||
generated_at: "2026-04-16T03:42:18.353896+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "b040e834d4537e76"
|
||||
---
|
||||
|
||||
# `DTS.Slice.Control.Event.Module.AnalogInputChannel.ReviewableAttribute` Implementations
|
||||
|
||||
## 1. Purpose
|
||||
This module provides a set of concrete `ReviewableAttribute` subclasses used to expose specific channel metadata and calibration-related values for review in the DTS Slice control/event system. Each attribute encapsulates a named, human-readable property of an `AnalogInputChannel` (e.g., serial number, filter settings, shunt calibration metrics), formatted as a string via a delegate. These attributes are intended for use in UI review workflows or audit logs where static or quasi-static channel configuration and calibration state must be presented consistently.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
All classes inherit from `Slice.Control.Event.Module.Channel.ReviewableAttribute`. Each constructor accepts a single `Event.Module.Channel` parameter and passes a display name and a `Func<string>` to the base constructor.
|
||||
|
||||
| Class | Constructor | Display Name | Behavior |
|
||||
|-------|-------------|--------------|----------|
|
||||
| `ReviewableShuntDeflectionAttribute` | `ReviewableShuntDeflectionAttribute(Channel)` | `"Shunt Deflection (mV)"` | Returns `channel.MeasuredShuntDeflectionMv.ToString("F1")`. Requires `channel` to implement `DTS.DAS.Concepts.DAS.Channel.IShuntAware`. |
|
||||
| `ReviewableFilterFrequencyAttribute` | `ReviewableFilterFrequencyAttribute(Channel)` | `"Filter Frequency"` | Returns `(int)(channel.CurrentFilter as SaeJ211Filter).CutoffFrequencyHz.ToString("N")`. Requires `channel.CurrentFilter` to be a `SaeJ211Filter`. |
|
||||
| `ReviewableIsoCodeAttribute` | `ReviewableIsoCodeAttribute(Channel)` | `"ISO Code"` | Returns `(channel as AnalogInputChannel).IsoCode.ToString()`. Requires `channel` to be an `AnalogInputChannel`. |
|
||||
| `ReviewableDescriptionAttribute` | `ReviewableDescriptionAttribute(Channel)` | `"Description"` | Returns `channel.ChannelDescriptionString`. |
|
||||
| `ReviewableSerialNumberAttribute` | `ReviewableSerialNumberAttribute(Channel)` | `"Serial Number"` | Returns `(channel as AnalogInputChannel).SerialNumber.ToString()`. Requires `channel` to be an `AnalogInputChannel`. |
|
||||
| `ReviewableUnitsAttribute` | `ReviewableUnitsAttribute(Channel)` | `"Units"` | Returns `channel.EngineeringUnits.ToString()`. Requires `channel` to implement `DTS.DAS.Concepts.DAS.Channel.IEngineeringUnitAware`. |
|
||||
| `ReviewableMinMaxEuAttribute` | `ReviewableMinMaxEuAttribute(Channel)` | `"Max/Min (EU)"` | Returns `channel.DataMaxFilteredEu.ToString("F1") + "/" + channel.DataMinFilteredEu.ToString("F1")`. |
|
||||
| `ReviewableCfcAttribute` | `ReviewableCfcAttribute(Channel)` | `"CFC"` | Returns `"N/A"` if `channel.CurrentFilter.Type == ChannelFilter.AdHoc`; otherwise returns `(new CfcValueAttributeCoder()).DecodeAttributeValue((channel.CurrentFilter as SaeJ211Filter).Type).ToString()`. Requires `channel.CurrentFilter` to be a `SaeJ211Filter`. |
|
||||
| `ReviewableTargetShuntDeflectionAttribute` | `ReviewableTargetShuntDeflectionAttribute(Channel)` | `"Target Shunt Deflection (mV)"` | Returns `channel.TargetShuntDeflectionMv.ToString("F1")`. Requires `channel` to implement `IShuntAware`. |
|
||||
| `ReviewableTargetCalSignalAttribute` | `ReviewableTargetCalSignalAttribute(Channel)` | `"Target Calibration Signal (mV)"` | Returns `channel.TargetCalSignalMv.ToString("F1")`. Requires `channel` to implement `DTS.DAS.Concepts.DAS.Channel.ICalSignalAware`. |
|
||||
| `ReviewableMeasuredShuntDeflectionAttribute` | `ReviewableMeasuredShuntDeflectionAttribute(Channel)` | `"Measured Shunt Deflection (mV)"` | Returns `channel.MeasuredShuntDeflectionMv.ToString("F1")`. Requires `channel` to implement `IShuntAware`. |
|
||||
| `ReviewableMeasuredCalSignalAttribute` | `ReviewableMeasuredCalSignalAttribute(Channel)` | `"Measured Calibration Signal (mV)"` | Returns `channel.MeasuredCalSignalMv.ToString("F1")`. Requires `channel` to implement `ICalSignalAware`. |
|
||||
| `ReviewableShuntDeflectionPercentageAttribute` | `ReviewableShuntDeflectionPercentageAttribute(Channel)` | `"Shunt Error (%)"` | Returns `100.0 * (MeasuredShuntDeflectionMv - TargetShuntDeflectionMv) / TargetShuntDeflectionMv.ToString("F1")`. Requires `channel` to implement `IShuntAware`. |
|
||||
| `ReviewableCalSignalPercentageAttribute` | `ReviewableCalSignalPercentageAttribute(Channel)` | `"Calibration Signal Error (%)"` | Returns `100.0 * (MeasuredCalSignalMv - TargetCalSignalMv) / TargetCalSignalMv.ToString("F1")`. Requires `channel` to implement `ICalSignalAware`. |
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **All attributes are read-only**: Each attribute’s value is computed on-demand via a delegate passed to the base class; no internal state is stored beyond the delegate capture.
|
||||
- **Type assumptions**: Each attribute assumes the `channel` parameter supports specific interfaces or concrete types:
|
||||
- `IShuntAware` for shunt-related attributes (`ReviewableShuntDeflectionAttribute`, `ReviewableTargetShuntDeflectionAttribute`, `ReviewableMeasuredShuntDeflectionAttribute`, `ReviewableShuntDeflectionPercentageAttribute`).
|
||||
- `ICalSignalAware` for calibration signal attributes (`ReviewableTargetCalSignalAttribute`, `ReviewableMeasuredCalSignalAttribute`, `ReviewableCalSignalPercentageAttribute`).
|
||||
- `IEngineeringUnitAware` for `ReviewableUnitsAttribute`.
|
||||
- `SaeJ211Filter` for `ReviewableFilterFrequencyAttribute` and `ReviewableCfcAttribute`.
|
||||
- `AnalogInputChannel` (via `as`) for `ReviewableIsoCodeAttribute` and `ReviewableSerialNumberAttribute`.
|
||||
- **Null-safety**: None of the attributes perform explicit null checks. If `channel` is `null`, or if the required interface/type cast fails (e.g., `channel.CurrentFilter` is not a `SaeJ211Filter`), a `NullReferenceException` or `InvalidCastException` will occur at evaluation time.
|
||||
- **Formatting consistency**: All numeric values are formatted with `"F1"` (1 decimal place) or `"N"` (thousands separator, no decimals) as shown.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Internal Dependencies (from source):
|
||||
- `DTS.Slice.Control.Event.Module.Channel.ReviewableAttribute` (base class, not shown but referenced).
|
||||
- `DTS.DAS.Concepts.DAS.Channel.IShuntAware`, `ICalSignalAware`, `IEngineeringUnitAware` (interfaces).
|
||||
- `DTS.DAS.Concepts.DAS.Channel.SaeJ211Filter`, `ChannelFilter` (types).
|
||||
- `DTS.Utilities.CfcValueAttributeCoder` (used in `ReviewableCfcAttribute`).
|
||||
- `DTS.Slice.Control.Event.Module.AnalogInputChannel` (namespace context and partial class definitions).
|
||||
|
||||
### External Dependencies:
|
||||
- `System` (core runtime).
|
||||
- `DTS.Utilities` (assembly reference required for `CfcValueAttributeCoder` and `SaeJ211Filter`).
|
||||
|
||||
### Inferred Usage:
|
||||
- These attributes are likely instantiated and collected by a higher-level component that iterates over `AnalogInputChannel` instances and exposes their reviewable metadata (e.g., for calibration reports or UI inspection panels). The repeated pattern suggests a factory or registration mechanism exists elsewhere (not visible here).
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **Ambiguous naming**: `ReviewableShuntDeflectionAttribute` (in first file) and `ReviewableMeasuredShuntDeflectionAttribute` (in later file) have identical implementation logic and display names. This duplication is likely unintentional or legacy; only one should be used, or naming should be clarified (e.g., “Shunt Deflection (mV)” vs. “Measured Shunt Deflection (mV)”).
|
||||
- **Missing null guards**: All attributes assume `channel` is non-null and implements required interfaces. A cast failure (e.g., `channel as DTS.DAS.Concepts.DAS.Channel.IShuntAware` returning `null`) will cause a `NullReferenceException` at delegate invocation time, not construction.
|
||||
- **`ReviewableCfcAttribute` logic**: The commented-out line suggests a previous implementation using `CfcValueAttributeCoder.DecodeAttributeValue` directly, but the current version adds a special case for `ChannelFilter.AdHoc`. This implies that `AdHoc` filters may not have a valid `Type` for decoding, and the attribute must handle this explicitly.
|
||||
- **`ReviewableFilterFrequencyAttribute` casts `channel.CurrentFilter` to `SaeJ211Filter` without checking**: If `CurrentFilter` is not a `SaeJ211Filter`, this will throw `InvalidCastException`.
|
||||
- **`ReviewableIsoCodeAttribute` comment is incorrect**: Its summary says “serial number attribute” but the class name and implementation clearly indicate it’s for ISO code. Likely copy-paste error in documentation.
|
||||
- **No validation of division-by-zero**: In `ReviewableShuntDeflectionPercentageAttribute` and `ReviewableCalSignalPercentageAttribute`, if `TargetShuntDeflectionMv` or `TargetCalSignalMv` is zero, a `DivideByZeroException` will occur.
|
||||
@@ -0,0 +1,302 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/Channel/DataValues.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/Channel/ReviewableAttribute.NotApplicableException.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/Channel/Filter.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/Channel/ChannelDefaultSaeJ211Filter.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/Channel/CalculatedChannel.cs
|
||||
- Common/DTS.Common.Serialization/Control/Event/Module/Channel/SaeJ211Filter.cs
|
||||
generated_at: "2026-04-16T03:42:34.925173+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "2400faf1f9897d63"
|
||||
---
|
||||
|
||||
# Documentation: `DTS.Slice.Control.Event.Module.Channel` Subsystem
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides core data structures and abstractions for representing and manipulating channel data within event recordings in the DTS Slice Control system. It defines the foundational types for physical channels, calculated channels, filters (including SAE J211–compliant filters), and data storage mechanisms (in-memory vs. memory-mapped). The subsystem enables filtering, unit conversion, and serialization of channel data, supporting both raw sensor inputs (ADC) and derived quantities (EU, mV), as well as computed channels (e.g., integrals, derivatives, FFTs). It serves as the data model layer for event analysis and review workflows.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### `DataValues` class
|
||||
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/DataValues.cs`*
|
||||
|
||||
- **`DataValues()`**
|
||||
Initializes a `DataValues` instance using in-memory storage (i.e., `UseMemoryMappedFile = false`).
|
||||
|
||||
- **`DataValues(bool useMemoryMappedFile)`**
|
||||
Initializes a `DataValues` instance. If `useMemoryMappedFile` is `true`, the instance is configured to use memory-mapped files for data storage (intended for large datasets exceeding process memory limits).
|
||||
|
||||
- **`UseMemoryMappedFile: bool`**
|
||||
Property controlling whether the instance uses memory-mapped files (`true`) or in-memory storage (`false`). Implemented via a `Property<bool>` wrapper.
|
||||
|
||||
---
|
||||
|
||||
### `Filter` abstract class
|
||||
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/Filter.cs`*
|
||||
|
||||
- **`Name: string` (abstract)**
|
||||
Returns a descriptive name for the filter (e.g., `"6G"` for a 6g filter, or `"123.45Hz"` for ad hoc).
|
||||
|
||||
- **`IsCfc: bool` (abstract)**
|
||||
Returns `true` if the filter corresponds to a defined CFC (Channel Filter Classification) value; `false` for `Unfiltered` or `AdHoc`.
|
||||
|
||||
- **`Type: ChannelFilter` (abstract)**
|
||||
Returns the canonical `ChannelFilter` enum value representing the filter (e.g., `ChannelFilter.SixG`, `ChannelFilter.AdHoc`).
|
||||
|
||||
- **`CutoffFrequencyHz: double` (abstract)**
|
||||
Returns the filter’s cutoff frequency in hertz.
|
||||
|
||||
- **`Apply(Channel input, DataDisplayUnits displayUnits, bool bUseLegacyTDCSoftwareFilterAdjustment): double[]` (abstract)**
|
||||
Applies the filter to the unfiltered data of the specified `input` channel, returning filtered data in the requested `displayUnits` (ADC, EU, or mV). The `bUseLegacyTDCSoftwareFilterAdjustment` flag controls whether a one-sample phase shift is applied to match legacy TDC behavior (see issue #8747).
|
||||
|
||||
- **`Apply(double[] data, double sampleRate, bool bUseLegacyTDCSoftwareFilterAdjustment): double[]` (abstract)**
|
||||
Applies the filter to a raw data array with known `sampleRate`, returning filtered data. Used when channel context is unavailable.
|
||||
|
||||
- **`ToBaseString(): string` (abstract)**
|
||||
Returns the filter’s base name (e.g., `"6G"`), without any decorative prefix (e.g., `"Default (6G)"`). Distinct from `ToString()`.
|
||||
|
||||
---
|
||||
|
||||
### `SaeJ211Filter` class
|
||||
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/SaeJ211Filter.cs`*
|
||||
|
||||
- **`SaeJ211Filter(ChannelFilter originalType)`**
|
||||
Initializes a filter for a CFC-compliant type (e.g., `ChannelFilter.SixG`). Throws `Exception` if `originalType == ChannelFilter.AdHoc`.
|
||||
|
||||
- **`SaeJ211Filter(double cutoffFrequencyHz)`**
|
||||
Initializes an ad hoc filter with the specified cutoff frequency.
|
||||
|
||||
- **`SaeJ211Filter(SaeJ211Filter originalFilter)`**
|
||||
Copy constructor.
|
||||
|
||||
- **`OriginalType: ChannelFilter`**
|
||||
Stores the original filter type passed at construction (e.g., `AdHoc` for ad hoc filters). Not modifiable after construction.
|
||||
|
||||
- **`Type: ChannelFilter` (override)**
|
||||
Returns the *effective* filter type: if `OriginalType == AdHoc`, resolves to the nearest matching CFC (or `AdHoc` if no match); otherwise returns `OriginalType`.
|
||||
|
||||
- **`IsCfc: bool` (override)**
|
||||
Returns `true` if `Type` is neither `Unfiltered` nor `AdHoc`.
|
||||
|
||||
- **`CutoffFrequencyHz: double` (override)**
|
||||
Returns the cutoff frequency in Hz (derived from `OriginalType` or explicitly set for ad hoc filters).
|
||||
|
||||
- **`IsoDescription: char`**
|
||||
Returns the first character of the ISO description for `OriginalType` (e.g., `'G'` for `SixG`).
|
||||
|
||||
- **`Name: string` (override)**
|
||||
Returns a human-readable name:
|
||||
- For `AdHoc`: `"123.45Hz"`
|
||||
- For CFC types: description from `DescriptionAttributeCoder<ChannelFilter>` (e.g., `"6G"`).
|
||||
|
||||
- **`Apply(...)` (override)**
|
||||
Implements filtering using `FilterUtility`. Supports filtering from `UnfilteredData`, `UnfilteredDataEu`, or `UnfilteredDataMv` depending on `displayUnits`. Logs warnings for invalid data via `APILogger`.
|
||||
|
||||
- **`Parse(string serialization): Filter` (static)**
|
||||
Parses a serialized filter string (e.g., `"6G"`, `"123.45Hz"`) into a `Filter` instance. Falls back to `Unfiltered` on parse failure.
|
||||
|
||||
- **`Equals(object obj): bool` (override)**
|
||||
Case-insensitive comparison of filter names.
|
||||
|
||||
- **`GetHashCode(): int` (override)**
|
||||
Hash code based on lowercase filter name.
|
||||
|
||||
- **`ToString(): string` (override)**
|
||||
Returns `Name`.
|
||||
|
||||
- **`ToBaseString(): string` (override)**
|
||||
Returns `Name`.
|
||||
|
||||
---
|
||||
|
||||
### `DefaultSaeJ211Filter` class
|
||||
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/ChannelDefaultSaeJ211Filter.cs`*
|
||||
|
||||
- **`DefaultSaeJ211Filter(SaeJ211Filter filter)`**
|
||||
Copy constructor.
|
||||
|
||||
- **`DefaultSaeJ211Filter(ChannelFilter filterType)`**
|
||||
Initializes with a CFC filter type.
|
||||
|
||||
- **`DefaultSaeJ211Filter(double adHocFrequency)`**
|
||||
Initializes with an ad hoc frequency.
|
||||
|
||||
- **`Name: string` (override)**
|
||||
Returns `"Default (" + base.Name + ")"` (e.g., `"Default (6G)"`).
|
||||
|
||||
- **`ToBaseString(): string` (override)**
|
||||
Returns `base.Name` (e.g., `"6G"`).
|
||||
|
||||
- **`ToString(): string` (override)**
|
||||
Returns `Name`.
|
||||
|
||||
---
|
||||
|
||||
### `CalculatedChannel` abstract class
|
||||
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/CalculatedChannel.cs`*
|
||||
|
||||
- **`Operation` enum**
|
||||
Defines supported calculations: `Integral`, `Derivative`, `HeadInjuryCriteria`, `FFT`, `ImportedCSV`, `Resultant`, `TSR`, `Scale`, `Offset`, `Sine`, `Cosine`.
|
||||
|
||||
- **`CalculationType: Operation`**
|
||||
Returns the operation performed by this channel.
|
||||
|
||||
- **`X: double[]`, `Y: double[]`**
|
||||
Read-only arrays of x-axis and y-axis data points.
|
||||
|
||||
- **`XAxis: XUnits`**
|
||||
X-axis unit type (`msec`, `sec`, `Hz`, `samples`).
|
||||
|
||||
- **`XUnitsString: string`**
|
||||
Human-readable unit string (e.g., `"ms"`, `"Hz"`).
|
||||
|
||||
- **`EngineeringUnits: string`**
|
||||
Y-axis engineering units (e.g., `"g"`, `"m/s"`).
|
||||
|
||||
- **`SupportsADC: bool` (override)**
|
||||
Always `false` for calculated channels.
|
||||
|
||||
- **`SupportsEU: bool` (override)**
|
||||
Always `true`.
|
||||
|
||||
- **`SupportsmV: bool` (override)**
|
||||
Always `false`.
|
||||
|
||||
- **`ActualMaxRangeEu`, `ActualMinRangeEu`, `DataMaxEu`, `DataMinEu`, `DataRangeEu`, `DataHalfRangeValueEu` (overrides)**
|
||||
Computed from `Y` data (e.g., `DataMaxEu = _y.Max()`).
|
||||
|
||||
- **`IsConfigured: bool` (override)**
|
||||
Always `true`; setting throws `NotSupportedException`.
|
||||
|
||||
- **`GetUnfilteredDataEu(): List<double>` (override)**
|
||||
Returns a copy of `Y`.
|
||||
|
||||
- **Constructors**
|
||||
- `CalculatedChannel(string name, XUnits xAxis, string yAxis, double[] xValues, double[] yValues, Operation calcType, int number, Module parentModule)`
|
||||
Initializes with data, axis labels, and calculation type. Sets `CurrentFilter` to `DefaultSaeJ211Filter(ChannelFilter.Unfiltered)`.
|
||||
|
||||
- **`ToString(): string` (override)**
|
||||
Returns `ChannelDescriptionString` or `"N/A"`.
|
||||
|
||||
---
|
||||
|
||||
### Derived `CalculatedChannel` classes
|
||||
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/CalculatedChannel.cs`*
|
||||
|
||||
- **`FFTCalculatedChannel`**
|
||||
- **`PeakFrequency: double`**
|
||||
Returns the peak frequency from the FFT.
|
||||
|
||||
- **`IntegralCalculatedChannel`, `DerivativeCalculatedChannel`, `ScaleCalculatedChannel`, `OffsetCalculatedChannel`, `ResultantCalculatedChannel`, `AdditiveVectorCalculatedChannel`, `SineCalculatedChannel`, `CosineCalculatedChannel`**
|
||||
All inherit from `CalculatedChannel` with no additional public members.
|
||||
|
||||
> **Note**: `HICCalculatedChannel` is commented out in source and not documented.
|
||||
|
||||
---
|
||||
|
||||
### `ReviewableAttribute.NotApplicableException` class
|
||||
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/ReviewableAttribute.NotApplicableException.cs`*
|
||||
|
||||
- **`NotApplicableException()`**
|
||||
Default constructor.
|
||||
|
||||
- **`NotApplicableException(string msg)`**
|
||||
Constructor with message.
|
||||
|
||||
- **`NotApplicableException(string msg, Exception innerEx)`**
|
||||
Constructor with message and inner exception.
|
||||
|
||||
> Inherits from `ApplicationException`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **`DataValues.UseMemoryMappedFile`**
|
||||
Once set during construction, this flag determines the storage strategy for channel data. No runtime switching is exposed.
|
||||
|
||||
- **`SaeJ211Filter.OriginalType`**
|
||||
Immutable after construction. `Type` may differ from `OriginalType` for ad hoc filters (resolved to nearest CFC or `AdHoc`).
|
||||
|
||||
- **`Filter.Type`**
|
||||
For ad hoc filters (`OriginalType == AdHoc`), `Type` is computed dynamically based on `CutoffFrequencyHz` (via `ConvertFrequencyToChannelFilter`). If frequency matches a CFC enum value, `Type` becomes that CFC; otherwise remains `AdHoc`.
|
||||
|
||||
- **`CalculatedChannel` properties**
|
||||
- `SupportsADC` and `SupportsmV` are always `false`; `SupportsEU` is always `true`.
|
||||
- Range properties (`ActualMaxRangeEu`, etc.) are derived from `Y` data and may change if `Y` is modified (though `Y` is read-only via public API).
|
||||
|
||||
- **`Filter.Apply(...)`**
|
||||
Filtering always uses `FilterUtility` with `Cfc = Type`, `AdHocFrequency = CutoffFrequencyHz`, and `SampleRate` from channel or parameter. Invalid data triggers logging and exception.
|
||||
|
||||
- **`Filter.Parse(...)`**
|
||||
Returns `Unfiltered` filter on parse failure (not `null`).
|
||||
|
||||
---
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Internal Dependencies (from source)
|
||||
- **`DTS.Common.Utilities`**
|
||||
Used for `Property<T>`, logging (`APILogger`), and encoding utilities (`CfcValueAttributeCoder`, `DescriptionAttributeCoder`, `IsoDescriptionAttributeCoder`).
|
||||
|
||||
- **`DTS.Slice.Control.DAS.Channel`**
|
||||
Referenced for `ChannelFilter` enum and `DataDisplayUnits` enum.
|
||||
|
||||
- **`DTS.Common.DAS.Concepts.DAS.Channel.IEngineeringUnitAware`**
|
||||
Implemented by `CalculatedChannel`.
|
||||
|
||||
- **Serialization types**
|
||||
`Serialization.SliceRaw.File.PersistentChannel`, `Serialization.TDAS.File.PersistentChannel`, `ILargeDataAware`, `Serialization.Test.Module.Channel`.
|
||||
|
||||
- **`DTS.Calculations.HeadInjuryCriterion.HICResult`**
|
||||
Referenced in commented-out `HICCalculatedChannel` code.
|
||||
|
||||
- **`DTS.Common.Utilities.SaeJ211`**
|
||||
Used for `FilterUtility` and related encoding.
|
||||
|
||||
### External Dependencies (inferred)
|
||||
- **`System`**
|
||||
Standard .NET types (`Exception`, `ApplicationException`, `CultureInfo`, `Enum`, etc.).
|
||||
|
||||
- **Windows Forms (commented)**
|
||||
`System.Windows.Forms.MessageBox` appears in commented-out code (not active).
|
||||
|
||||
---
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **`DataValues` has no data storage logic**
|
||||
The class only configures storage mode (`UseMemoryMappedFile`). Actual data handling is delegated to `Channel` (not shown in these files). `DataValues` is a configuration helper, not a data container.
|
||||
|
||||
- **`SaeJ211Filter.Type` may differ from `OriginalType`**
|
||||
For ad hoc filters, `Type` resolves to the nearest CFC match. This can cause `IsCfc` to return `true` even if `OriginalType == AdHoc`.
|
||||
|
||||
- **`Filter.Parse(...)` silently falls back to `Unfiltered`**
|
||||
On parse failure, returns `new SaeJ211Filter(ChannelFilter.Unfiltered)` instead of throwing. Callers must validate if needed.
|
||||
|
||||
- **`DefaultSaeJ211Filter.ToString()` vs `ToBaseString()`**
|
||||
`ToString()` returns `"Default (X)"`, while `ToBaseString()` returns `"X"`. Confusing if not documented.
|
||||
|
||||
- **`CalculatedChannel` range properties assume non-empty `Y`**
|
||||
`DataMaxEu`, `DataMinEu`, etc., use `_y.Max()`/`_y.Min()` without checking for empty data. Will throw `InvalidOperationException` if `Y` is empty.
|
||||
|
||||
- **`SupportsADC`/`SupportsmV` are hard-coded `false`**
|
||||
Calculated channels never support raw ADC or mV; only engineering units (EU). Attempting to access `ActualMinRangeMv` throws `NotImplementedException`.
|
||||
|
||||
- **`CalculatedChannel` serialization methods throw `NotSupportedException`**
|
||||
`FromDtsSerializationTestModuleChannel`, `ToDtsSerializationTestModuleChannel`, `SetPropertyValuesFrom(...)` all throw. Calculated channels are not serializable via these paths.
|
||||
|
||||
- **`Filter.Apply(...)` logs invalid data but throws**
|
||||
`FilterUtility.InvalidDataDelegate` logs via `APILogger` but then throws an exception. No silent failure.
|
||||
|
||||
- **`ChannelFilter` enum values are used as frequencies**
|
||||
CFC filters (e.g., `ChannelFilter.SixG`) are implicitly cast to `double` for frequency. This relies on enum underlying values matching CFC frequencies.
|
||||
|
||||
- **`IsoDescription` uses `OriginalType`**
|
||||
The ISO description character is derived from `OriginalType`, not `Type`. For ad hoc filters, this may be `Unfiltered` (not meaningful).
|
||||
|
||||
- **`DataValues` constructor catches and rethrows as `Exception`**
|
||||
Any exception during construction is wrapped in a generic `Exception` with a message like `"encountered problem constructing DTS.Slice.Control.Event.Module.Channel.DataValues"`. Original exception is preserved in `InnerException`.
|
||||
@@ -0,0 +1,325 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/DDAS (Chrysler)/ChannelDefinition.h
|
||||
- Common/DTS.Common.Serialization/DDAS (Chrysler)/DDASTestDefinition.h
|
||||
- Common/DTS.Common.Serialization/DDAS (Chrysler)/DataFloat.h
|
||||
- Common/DTS.Common.Serialization/DDAS (Chrysler)/DDAS.File.cs
|
||||
- Common/DTS.Common.Serialization/DDAS (Chrysler)/DDASTest.cs
|
||||
- Common/DTS.Common.Serialization/DDAS (Chrysler)/DDAS.File.Writer.cs
|
||||
- Common/DTS.Common.Serialization/DDAS (Chrysler)/TSVSettingsWindow.cs
|
||||
- Common/DTS.Common.Serialization/DDAS (Chrysler)/TSVSettingsWindow.Designer.cs
|
||||
- Common/DTS.Common.Serialization/DDAS (Chrysler)/DDASChannel.cs
|
||||
generated_at: "2026-04-16T13:34:29.248067+00:00"
|
||||
model: "zai-org/GLM-5-FP8"
|
||||
schema_version: 1
|
||||
sha256: "3efc64a6d144d6f5"
|
||||
---
|
||||
|
||||
# DDAS Serialization Module Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides serialization and deserialization support for the DDAS (DaimlerChrysler Data Acquisition System) file format, a proprietary binary format used for storing crash test data. It bridges legacy C/C++ data structures (originally from DaimlerChrysler's DDAS V5 system) with modern .NET serialization infrastructure, enabling export of test data including channel configurations, transducer information, and floating-point measurement data. The module handles both the file format definitions and the actual binary writing of channel data.
|
||||
|
||||
---
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### C/C++ Structures (Header Files)
|
||||
|
||||
#### `ChannelDefinition.h`
|
||||
|
||||
**`enum ChannelFlags`**
|
||||
- `CHANFLAG_ACTIVE` - Flag indicating an active channel
|
||||
|
||||
**Macros:**
|
||||
- `ISCHANACTIVE(pChan)` - Returns 1 if channel is active, 0 otherwise
|
||||
- `SETCHANACTIVE(pChan)` - Sets the active flag on a channel
|
||||
- `CLRCHANACTIVE(pChan)` - Clears the active flag on a channel
|
||||
|
||||
**`struct tagCHANNEL` / `CHANNEL` / `PCHANNEL` / `PCHAN`**
|
||||
- `short Size` - Size of this object
|
||||
- `short Flags` - Channel flags
|
||||
- `char Name[64]` - Channel name
|
||||
- `char Sign[8]` - Sign (+, -, or blank)
|
||||
- `char Axis[8]` - Axis designation (X, Y, Z, FX, MX, AX, etc.)
|
||||
- `float FilterFreq` - Channel filter class in Hz
|
||||
- `float SetGain` - Gain setting (1 - n)
|
||||
- `float ActGain` - Actual (measured) gain setting
|
||||
- `float Rcal` - Shunt calibration resistance
|
||||
- `float Excitation` - Excitation voltage (when programmable)
|
||||
- `byte byteSpares[4]` - Spare bytes (was CalDate, removed 11/08/04)
|
||||
- `TRANSDUCER Transducer` - Snapshot of transducer values
|
||||
|
||||
---
|
||||
|
||||
#### `DDASTestDefinition.h`
|
||||
|
||||
**`enum FileTypeFlags`**
|
||||
- `FILETYPE_IMPORTED4X` - Test was imported from 4x format
|
||||
|
||||
**`enum HardwareType`**
|
||||
- `HWTYPE_UNKNOWN` - None specified (old DDAS)
|
||||
- `HWTYPE_DDAS3` - DDAS III hardware
|
||||
- `HWTYPE_KAYSERTHREDE` - Kayser-Threde hardware (future)
|
||||
- `HWTYPE_COUNT` - Count of hardware types
|
||||
|
||||
**`struct tagFILEINFOBLOCK` / `FILEINFOBLOCK`**
|
||||
- `UINT Size` - Block size including nSize
|
||||
- `char FileTypeName[12]` - Software type name
|
||||
- `char FileTypeVers[12]` - File version name
|
||||
- `UINT FileTypeFlags` - Hardware type in upper 16 bits, File type in lower 16 bits
|
||||
- `char CreatedByName[16]` - Created by T-number
|
||||
- `char UpdatedByName[16]` - Updated by T-number
|
||||
|
||||
**`struct tagDATASYSTEMBLOCK` / `DATASYSTEMBLOCK`**
|
||||
- `UINT Size`, `NumberOfSystems`, `ChannelsPerSystem`, `MaxSampleRate`, `SizeOfConfig`
|
||||
|
||||
**`struct tagDDASCONFIGBLOCK` / `DDASCONFIGBLOCK`**
|
||||
- `UINT Size`
|
||||
- `short AnalogUnitNo`, `AnalogOptions`, `MemoryUnitNo`, `MemoryOptions`
|
||||
- `long MemorySize`
|
||||
|
||||
**`enum AnalogOptionFlags`**
|
||||
- `ANAOPT_CHANTRIGGERS` - Analog unit has channel triggers
|
||||
|
||||
**`enum MemoryOptionFlags`**
|
||||
- `MEMOPT_TAPEMODE` - Memory unit has tape mode
|
||||
- `MEMOPT_PREEVENT` - Memory unit can select pre-event to 99
|
||||
- `MEMOPT_PREEVENTXXX` - Memory unit can select pre-event to 511
|
||||
|
||||
**`enum RecordModes`**
|
||||
- `RECORDMODE_EVENT` - Normal (event) mode
|
||||
- `RECORDMODE_TAPE` - Tape (manual) mode
|
||||
|
||||
**`struct tagACQUISITIONBLOCK` / `ACQUISITIONBLOCK`**
|
||||
- `long nSize`, `nRecordMode`, `SampleRate`, `TotalSamples`, `PreEventSamples`, `TapeModeChannels`, `nTrigBlock`
|
||||
|
||||
**`struct tagTRIGCHANDEF` / `TRIGCHANDEF`**
|
||||
- `BYTE ChanNo` - Channel number to use as trigger
|
||||
- `BYTE LevelPct` - Trigger level in % full scale (0 = off)
|
||||
|
||||
**Constants:**
|
||||
- `MAXTRIGCHANS` = 4
|
||||
- `TRIGCHANDSBL` = 0x80
|
||||
|
||||
**`struct tagTRIGCHANBLOCK` / `TRIGCHANBLOCK`**
|
||||
- `unsigned short SizeBlock`, `NumTrigs`
|
||||
- `TRIGCHANDEF TrigChan[MAXTRIGCHANS]`
|
||||
|
||||
---
|
||||
|
||||
#### `DataFloat.h`
|
||||
|
||||
**`enum FileTypes`**
|
||||
- `UNKNOWN`, `FLOATPOINT`, `PROCESSED`
|
||||
|
||||
**`struct tagTESTINFO` / `TESTINFO`**
|
||||
- `unsigned long Size`, `DeviceID`
|
||||
- `long ChannelNo`, `SampleRate`, `TotalSamples`, `PreEventSamples`
|
||||
- `short ChanNumInSys`, `NumPreCalPts`, `NumPostCalPts`
|
||||
- `char TestCreation[128]`, `TimeAxisTitle[32]`
|
||||
- `byte SpareBytes[2]`
|
||||
|
||||
**`struct tagFILEHEADER` / `FILEHEADER`**
|
||||
- `FILEINFOBLOCK FileInfo`
|
||||
- `TESTINFO TestInfo`
|
||||
- `CHANNEL Channel`
|
||||
- `byte SpareBytes[32]`
|
||||
|
||||
**`struct tagDATAPEAK` / `DATAPEAK` / `PDATAPEAK` / `LPDP`**
|
||||
- `float Min`, `Max`
|
||||
- `short Xmin`, `Xmax`
|
||||
|
||||
**`enum PeakTypes`**
|
||||
- `PEAKS_MINMAX`, `PEAKS_3MSCONTIN`, `PEAKS_3MSCUMUL`
|
||||
|
||||
**`struct tagDATAHIST` / `DATAHIST`**
|
||||
- `float fVal` - Data value
|
||||
- `int nOccurrences` - Number of occurrences
|
||||
|
||||
**`class CDataFloat`**
|
||||
- `CDataFloat(unsigned int nSize)` / `CDataFloat()` - Constructors
|
||||
- `virtual ~CDataFloat()` - Destructor
|
||||
- `int GetChannelNumberInBox()`
|
||||
- `bool VerifyAndCoerceAxis(bool bNegativeSign, const char* szAxis, BOOL bVerbose)`
|
||||
- `void SetEngrgUnits(char *szNewEngrgUnits)`
|
||||
- `void SetChannelName(char* szNewChannelName)`
|
||||
- `int CalcSampIn3mSecInt()`
|
||||
- `int ConvertTimeToIndex(float fTime)`
|
||||
- `float ConvertIndexToTime(int nIndex)`
|
||||
- `const CString GetFileName()`
|
||||
- `int AppendArrayFloat(CArray<float, float&>* srcArray)`
|
||||
- `CArray<float, float&>* GetDataArray()`
|
||||
- `bool GetTimeAtValue(float fValue, float *pTvalue)`
|
||||
- `bool GetDataPeaks(...)` - Multiple overloads for peak detection
|
||||
- `int GetChannelNumber()`
|
||||
- `float GetStartTime(bool bmSec)` / `GetStartTimeData(bool bmSec)`
|
||||
- `float GetStopTime(bool bmSec)` / `GetStopTimeData(bool bmSec)`
|
||||
- `const char* GetFileExt()` / `GetFileTitle()`
|
||||
- `long GetSampleRate()`
|
||||
- `const char* GetFilePathAndName()`
|
||||
- `int SetFilePathAndName(char* szNewFileSpec)`
|
||||
- `int ClearAll(long NewNumberElements)`
|
||||
- `TESTINFO* GetTestInfo()`
|
||||
- `FILEINFOBLOCK* GetFileInfo()`
|
||||
- `CHANNEL* GetChannel()`
|
||||
- `float GetFilterClass()`
|
||||
- `int GetEventOffset()`
|
||||
- `CString GetDataSetName(CString &csName)`
|
||||
- `FILEHEADER* GetFileHeader()`
|
||||
- `bool WriteToFile(const char *lpFilename, bool bPrint)`
|
||||
- `bool ReadFromFile(const char *lpFilename)`
|
||||
- `float* GetDataBuffer()`
|
||||
- `bool SetSize(long lNumberElements)`
|
||||
- `long GetSize()`
|
||||
- `bool GetDataNext(float* fData)`
|
||||
- `bool StoreDataNext(float fData)`
|
||||
- `bool SetIndexToStart()`
|
||||
- `void operator=(const CDataFloat &src)`
|
||||
|
||||
**`class CDataFloat::CPeakList`**
|
||||
- `void RemoveAll()`
|
||||
- `void AddDataPoint(DATAHIST* pDHist)`
|
||||
- `void Get3msMin(int nPtPer3ms, DATAHIST* pDHist)`
|
||||
- `void Get3msMax(int nPtPer3ms, DATAHIST* pDHist)`
|
||||
|
||||
---
|
||||
|
||||
### C# Classes
|
||||
|
||||
#### `DDAS.File.cs`
|
||||
|
||||
**`class File : Serialization.File, IWritable<Test>`**
|
||||
- `File()` - Constructor, initializes with "DDAS" format identifier
|
||||
- `static string Extension` => ".ddas"
|
||||
- `IWriter<Test> Exporter` - Gets the file writer (lazy-initialized)
|
||||
|
||||
---
|
||||
|
||||
#### `DDASTest.cs`
|
||||
|
||||
**`class DDASTest`**
|
||||
- `enum Fields` - LabName, POCName, POCPhoneAndEmail, TestDate, TestTime, TestNumber, TestType, TestObject, DataType, SensorMakeModelSerial, SensorLocation, SensorAxis, SensorMountType, EngineeringUnits, ChannelErrors, SamplingRate, AAFilterCutoffDescription, BitResolution, DigitalFilterType, Notes
|
||||
- `string GetValue(Fields field)` - Returns "#NOVALUE" if field not set
|
||||
- `void SetValue(Fields field, string value)` - Sets value and propagates to all channels
|
||||
- `DDASChannel[] Channels` - Get/set channel array
|
||||
- `Test Test` - Associated test object
|
||||
- `FilteredData[] DataUnfilteredEU` - Unfiltered engineering unit data
|
||||
- `FilteredData[] DataADC` - ADC data
|
||||
- `double[] ActualRangesEUFiltered`, `ActualRangesEUUnfiltered`, `ActualRangesADC`
|
||||
- `bool FlatFolders`
|
||||
- Constructor: `DDASTest(Test test, FilteredData[] adc, FilteredData[] euUnfiltered, string path, double[] actualRangesEUFiltered, double[] actualRangesEUUnfiltered, double[] actualRAngesADC, bool flatFolders)`
|
||||
|
||||
---
|
||||
|
||||
#### `DDASChannel.cs`
|
||||
|
||||
**`class DDASChannel`**
|
||||
- `string GetValue(DDASTest.Fields field)` - Returns "#NOVALUE" if not set
|
||||
- `void SetValue(DDASTest.Fields field, string value)` - Sets field; special handling for DataType ("Raw", "Processed", "Converted")
|
||||
- `string FileName` - Output file path
|
||||
- `void Serialize(TickEventHandler tickHandler)` - Writes binary DDAS file
|
||||
- `int ChannelNumber` - Returns 1 + channelIndex
|
||||
- Constructor: `DDASChannel(DDASTest parentTest, int channelIndex, string path)`
|
||||
|
||||
---
|
||||
|
||||
#### `DDAS.File.Writer.cs`
|
||||
|
||||
**`class File.Writer : Writer<File>, IWriter<Test>`**
|
||||
- `internal Writer(File fileType, int encoding)` - Constructor
|
||||
- `void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)` - **Throws NotImplementedException**
|
||||
- `void Write(string pathname, string id, string dataFolder, Test test, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Test.Module.Channel tmChannel, int channelNumber, BeginEventHandler beginEventHandler, CancelEventHandler cancelEventHandler, EndEventHandler endEventHandler, TickEventHandler tickEventHandler, ErrorEventHandler errorEventHandler, CancelRequested cancelRequested, double minStartTime, int dataCollectionLength)` - Writes test via `MyTVTTest.Channels[].Serialize()`
|
||||
- `void Initialize(...)` - Empty implementation
|
||||
- `int DataSamplesPerTick` => 1000
|
||||
- `string ExtensionPrefix` - Property with getter/setter
|
||||
- `DDASTest MyTVTTest` - Property with getter/setter
|
||||
|
||||
---
|
||||
|
||||
#### `TSVSettingsWindow.cs`
|
||||
|
||||
**`class TSVSettingsWindow : Form`**
|
||||
- Constructor: `TSVSettingsWindow(TSVTest test)` - Initializes grids with test fields and channel data
|
||||
- `void button1_Click(object sender, EventArgs e)` - Sets DialogResult.OK and closes
|
||||
- Event handlers: `c1GridGlobal_CellChanged`, `gridChannels_CellChanged`, `c1GridChannels_AfterEdit`, `c1GridGlobal_AfterEdit`
|
||||
|
||||
---
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
### Binary Format Constraints
|
||||
- `FILEHEADER` total size is fixed; spare bytes must total 32 bytes for alignment
|
||||
- `TESTINFO.SpareBytes` must be exactly 2 bytes for 4-byte alignment
|
||||
- `TRIGCHANBLOCK.TrigChan` array is sized to `MAXTRIGCHANS` (4) but documented as variable-size
|
||||
- `FILEINFOBLOCK.FileTypeFlags` encodes Hardware Type in upper 16 bits, File Type in lower 16 bits
|
||||
|
||||
### Channel Numbering
|
||||
- Channel numbers are 1-indexed in output (`ChannelNumber => 1 + _channelIndex`)
|
||||
- `ChanNumInSys` is 1-128 range (for multi-device systems)
|
||||
|
||||
### Trigger Configuration
|
||||
- To enable a trigger: `ChanNo` and `LevelPct` must be nonzero, and `TRIGCHANDSBL` (0x80) must NOT be set in `LevelPct`
|
||||
- Maximum 4 trigger channels (`MAXTRIGCHANS`)
|
||||
|
||||
### File Naming
|
||||
- DDAS extension: `.ddas`
|
||||
- Float data extension: `.fpd`
|
||||
- Raw data extension: `.raw`
|
||||
|
||||
### Data Serialization
|
||||
- All string fields are ASCII-encoded and null-padded to their fixed sizes
|
||||
- Calibration date stored as seconds since 1971-01-01 (not Unix epoch 1970)
|
||||
|
||||
---
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### C/C++ Dependencies
|
||||
- `TransducerDefinition.h` - Required by `ChannelDefinition.h` for `TRANSDUCER` struct
|
||||
- `FilePath.h` - Required by `DataFloat.h` for `CFilePath` class
|
||||
- `<Afxtempl.h>` - MFC template collections (`CArray`, `CList`)
|
||||
|
||||
### .NET Dependencies
|
||||
- `System.Windows.Forms` - UI components in `TSVSettingsWindow`
|
||||
- `C1.Win.C1FlexGrid` - Third-party grid control
|
||||
- `System.IO` - File and directory operations
|
||||
- `System.Text` - ASCII encoding for binary output
|
||||
|
||||
### Inferred External Dependencies
|
||||
- `DTS.Serialization` namespace - Base `Serialization.File`, `Test`, `FilteredData` classes
|
||||
- `Test.Module.AnalogInputChannel` - Channel abstraction with properties like `Description`, `SerialNumber`, `EngineeringUnits`, `Sensitivity`, etc.
|
||||
|
||||
### Consumers
|
||||
- The `Writer` class is consumed by whatever orchestrates test exports (not shown in source)
|
||||
- `TSVSettingsWindow` consumes `TSVTest` and `TSVChannel` (referenced but not defined in provided sources)
|
||||
|
||||
---
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
### Historical Artifacts
|
||||
1. **Removed CalDate field**: The `CHANNEL` struct's `CalDate` was removed on 11/08/04 and replaced with `byteSpares[4]`. The calibration date now lives in the `TRANSDUCER` structure.
|
||||
|
||||
2. **Non-Unix Epoch**: The calibration date in `DDASChannel.Serialize()` uses `new DateTime(1971, 1, 1)` as the epoch, NOT the standard Unix epoch (1970-01-01). Comment says "Good til 2038...shouldn't be an issue for this developer."
|
||||
|
||||
3. **Typo in parameter name**: `DDASTest` constructor has parameter `actualRAngesADC` (typo: "RAnges" instead of "Ranges").
|
||||
|
||||
### Incomplete Implementation
|
||||
4. **NotImplementedException**: `Writer.Write(string pathname, string id, Test test, ...)` throws `NotImplementedException`. Only the overload with event handlers is functional.
|
||||
|
||||
5. **Empty Initialize method**: `Writer.Initialize()` has an empty body.
|
||||
|
||||
### File Format Quirks
|
||||
6. **Hardcoded magic values**: The `Serialize()` method writes hardcoded sizes (`0x40`, `0xC0`, `0x1001`, `0x0100`) without reference to the struct definitions.
|
||||
|
||||
7. **SLICE-specific assumption**: Comment in `DDASChannel` constructor: "AFAIK, in this context, there is no way other than assumption to know a bridge has three channels." The calculation `(channel.ParentModule.NumberOfChannels + 2) / 3 * 3` assumes 3 channels per bridge module.
|
||||
|
||||
8. **Variable-size array workaround**: `TRIGCHANBLOCK.TrigChan` is sized to `MAXTRIGCHANS` (4) to avoid compiler warnings, but the comment indicates it's intended to be variable-size.
|
||||
|
||||
### UI Threading
|
||||
9. **Volatile flag**: `TSVSettingsWindow._bPopulating` is marked `volatile` but used for UI state management during event handling—this pattern may have race conditions in edge cases.
|
||||
|
||||
### Data Type Mismatches
|
||||
10. **Mixed type usage**: `DDASChannel.Serialize()` writes `uint`
|
||||
@@ -0,0 +1,274 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/DDAS (Chrysler)/FromChrysler/ChannelDefinition.h
|
||||
- Common/DTS.Common.Serialization/DDAS (Chrysler)/FromChrysler/FilePath.h
|
||||
- Common/DTS.Common.Serialization/DDAS (Chrysler)/FromChrysler/DDASTestDefinition.h
|
||||
- Common/DTS.Common.Serialization/DDAS (Chrysler)/FromChrysler/DataFloat.h
|
||||
generated_at: "2026-04-16T13:34:29.272087+00:00"
|
||||
model: "zai-org/GLM-5-FP8"
|
||||
schema_version: 1
|
||||
sha256: "289fd9f58c0583bc"
|
||||
---
|
||||
|
||||
# DDAS Serialization Module Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides data structures and classes for the DDAS (DaimlerChrysler Data Acquisition System) proprietary file format serialization. It defines binary file layouts for test definitions, channel configurations, transducer definitions, and floating-point data storage used in automotive crash testing applications. The module enables reading, writing, and manipulation of DDAS test files (`.tdf`, `.fpd`, `.raw` extensions) and provides utilities for file path handling, peak detection, and data analysis.
|
||||
|
||||
---
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### ChannelDefinition.h
|
||||
|
||||
#### Enumerations
|
||||
- **`ChannelFlags`** — Channel flag values with single member `CHANFLAG_ACTIVE`
|
||||
|
||||
#### Macros
|
||||
- **`ISCHANACTIVE(pChan)`** — Returns 1 if channel active flag is set, 0 otherwise
|
||||
- **`SETCHANACTIVE(pChan)`** — Sets the channel active flag
|
||||
- **`CLRCHANACTIVE(pChan)`** — Clears the channel active flag
|
||||
|
||||
#### Structures
|
||||
- **`CHANNEL`** (typedef `tagCHANNEL`) — Main channel data structure containing:
|
||||
- `short Size` — Size of this object
|
||||
- `short Flags` — Channel flags
|
||||
- `char Name[64]` — Channel name
|
||||
- `char Sign[8]` — Sign (+, -, or blank)
|
||||
- `char Axis[8]` — Axis identifier (X, Y, Z, FX, MX, AX, etc.)
|
||||
- `float FilterFreq` — Filter frequency in Hz
|
||||
- `float SetGain` — Gain setting (1-n)
|
||||
- `float ActGain` — Actual/measured gain setting
|
||||
- `float Rcal` — Shunt calibration resistance
|
||||
- `float Excitation` — Excitation voltage (when programmable)
|
||||
- `byte byteSpares[4]` — Spare bytes (formerly `CalDate`)
|
||||
- `TRANSDUCER Transducer` — Snapshot of transducer values
|
||||
|
||||
#### Type Definitions
|
||||
- **`PCHANNEL`** — Pointer to `CHANNEL`
|
||||
- **`PCHAN`** — Alias for `PCHANNEL`
|
||||
|
||||
---
|
||||
|
||||
### FilePath.h
|
||||
|
||||
#### Constants
|
||||
- **`PATHLENMAX`** — Maximum path length allowed (300)
|
||||
|
||||
#### Enumerations
|
||||
- **`FileSpecOK`** — File specification validation flags:
|
||||
- `FSPEC_EXTOK = 0x1` — File extension valid
|
||||
- `FSPEC_NAMEOK = 0x2` — File name valid
|
||||
- `FSPEC_PATHOK = 0x4` — File path valid
|
||||
- `FSPEC_ROOTOK = 0x8` — Drive or computer valid
|
||||
- `FSPEC_RELATIVEPATH = 0x10` — Path is relative
|
||||
|
||||
#### Class `CFilePath`
|
||||
|
||||
**Public Methods:**
|
||||
- **`CFilePath()`** — Default constructor
|
||||
- **`virtual ~CFilePath()`** — Virtual destructor
|
||||
- **`void operator=(const CFilePath &src)`** — Assignment operator
|
||||
- **`int SetDrive(int nDriveAis1)`** — Sets drive where A=1
|
||||
- **`int SetDriveOrResource(char *szNewDrive, int* nNext)`** — Sets drive or network resource
|
||||
- **`int SetDir(char *szNewDir, int* nNext)`** — Sets directory path
|
||||
- **`int SetFile(char *szNewFile, int *nNext)`** — Sets filename
|
||||
- **`int SetExtension(char *szNewExt)`** — Sets file extension
|
||||
- **`int SetFullFilePathAndName(char* szPathAndName)`** — Sets complete path from string
|
||||
- **`int ParseFilePathAndName(char *szPathAndName)`** — Parses path and name into components
|
||||
- **`const char* GetFullFilePathAndName()`** — Returns complete path string
|
||||
- **`const char* GetFileName()`** — Returns filename without extension
|
||||
- **`const char* GetFileExtension()`** — Returns file extension
|
||||
- **`const CString GetFileNameExt()`** — Returns filename with extension
|
||||
- **`BOOL FileExists()`** — Tests if file exists
|
||||
- **`bool IsFileType(char *szFileTypeExt)`** — Checks if extension matches
|
||||
- **`bool IsPathComplete(int *pFlgValid)`** — Checks if path is complete
|
||||
- **`bool IsAllValidChars(char* szInString, int* pnPosBad)`** — Validates characters in string
|
||||
- **`bool IsFileValid(const char* szFileSpec, const char *szFileTypeExt, CString* pcsError)`** — Validates file specification
|
||||
- **`void Clear()`** — Clears all path components
|
||||
|
||||
---
|
||||
|
||||
### DDASTestDefinition.h
|
||||
|
||||
#### Constants
|
||||
- **`TESTDEFEXT`** — Test definition file extension (".tdf")
|
||||
- **`DDASTYPENAME`** — Software type name ("DDAS V5")
|
||||
- **`DDASFILEVERS`** — File version ("Ver 500")
|
||||
- **`MAXTRIGCHANS`** — Maximum trigger channels (4)
|
||||
- **`TRIGCHANDSBL`** — Trigger channel disable flag (0x80)
|
||||
|
||||
#### Enumerations
|
||||
- **`FileTypeFlags`** — File type flags with `FILETYPE_IMPORTED4X`
|
||||
- **`HardwareType`** — Hardware types: `HWTYPE_UNKNOWN`, `HWTYPE_DDAS3`, `HWTYPE_KAYSERTHREDE`, `HWTYPE_COUNT`
|
||||
- **`AnalogOptionFlags`** — `ANAOPT_CHANTRIGGERS` for channel trigger support
|
||||
- **`MemoryOptionFlags`** — `MEMOPT_TAPEMODE`, `MEMOPT_PREEVENT`, `MEMOPT_PREEVENTXXX`
|
||||
- **`RecordModes`** — `RECORDMODE_EVENT`, `RECORDMODE_TAPE`
|
||||
|
||||
#### Structures
|
||||
- **`FILEINFOBLOCK`** — File metadata:
|
||||
- `UINT Size` — Block size including Size field
|
||||
- `char FileTypeName[12]` — Software type name
|
||||
- `char FileTypeVers[12]` — File version
|
||||
- `UINT FileTypeFlags` — Hardware type (upper 16 bits) and file type (lower 16 bits)
|
||||
- `char CreatedByName[16]` — Creator T-number
|
||||
- `char UpdatedByName[16]` — Updater T-number
|
||||
|
||||
- **`DATASYSTEMBLOCK`** — Data system configuration:
|
||||
- `UINT Size` — Block size
|
||||
- `UINT NumberOfSystems` — Number of systems
|
||||
- `UINT ChannelsPerSystem` — Channels per system
|
||||
- `UINT MaxSampleRate` — Maximum/default sample rate
|
||||
- `UINT SizeOfConfig` — Size of one `DDASCONFIGBLOCK`
|
||||
|
||||
- **`DDASCONFIGBLOCK`** — Per-system configuration:
|
||||
- `UINT Size` — Block size
|
||||
- `short AnalogUnitNo` — Analog unit number
|
||||
- `short AnalogOptions` — Analog unit options
|
||||
- `short MemoryUnitNo` — Memory unit number
|
||||
- `short MemoryOptions` — Memory unit options
|
||||
- `long MemorySize` — Memory unit RAM in bytes
|
||||
|
||||
- **`ACQUISITIONBLOCK`** — Data acquisition parameters:
|
||||
- `long nSize` — Block size
|
||||
- `long nRecordMode` — Record mode (from `RecordModes` enum)
|
||||
- `long SampleRate` — Samples per second
|
||||
- `long TotalSamples` — Total samples in record
|
||||
- `long PreEventSamples` — Pre-event samples (event mode only)
|
||||
- `long TapeModeChannels` — Channel count (tape mode only)
|
||||
- `long nTrigBlock` — Number of trigger entries (can be 0)
|
||||
|
||||
- **`TRIGCHANDEF`** — Channel trigger definition:
|
||||
- `BYTE ChanNo` — Channel number for trigger
|
||||
- `BYTE LevelPct` — Trigger level as % full scale (0=off, 0x80=disabled)
|
||||
|
||||
- **`TRIGCHANBLOCK`** — Trigger channel collection:
|
||||
- `unsigned short SizeBlock` — Block size in bytes
|
||||
- `unsigned short NumTrigs` — Number of trigger entries
|
||||
- `TRIGCHANDEF TrigChan[MAXTRIGCHANS]` — Trigger definitions array
|
||||
|
||||
---
|
||||
|
||||
### DataFloat.h
|
||||
|
||||
#### Constants
|
||||
- **`TESTPATHSIZE`** — Test path size (128)
|
||||
- **`FILEERROR`** — File I/O error code (-1)
|
||||
- **`FLOATDATANAME`** — Float data file type ("DDAS FlPt")
|
||||
- **`FLOATDATARAW`** — Raw float data type ("DDAS fpRAW")
|
||||
- **`FLOATDATAVER`** — Float data version ("Ver 500")
|
||||
- **`RawExt`** — Raw data extension (".raw")
|
||||
- **`FlPtExt`** — Floating point data extension (".fpd")
|
||||
|
||||
#### Enumerations
|
||||
- **`FileTypes`** — `UNKNOWN`, `FLOATPOINT`, `PROCESSED`
|
||||
- **`PeakTypes`** — `PEAKS_MINMAX`, `PEAKS_3MSCONTIN`, `PEAKS_3MSCUMUL`
|
||||
- **`FPDVerbosity`** — `FPD_SILENT`, `FPD_ERRORS`, `FPD_STATUS`, `FPD_RESULTS`, `FPD_VERBOSE`
|
||||
|
||||
#### Structures
|
||||
- **`TESTINFO`** — Test information block:
|
||||
- `unsigned long Size` — Block size
|
||||
- `unsigned long DeviceID` — DAQ device ID
|
||||
- `long ChannelNo` — Channel number (1-32)
|
||||
- `long SampleRate` — Samples per second
|
||||
- `long TotalSamples` — Total samples in record
|
||||
- `long PreEventSamples` — Samples before event
|
||||
- `short ChanNumInSys` — Channel number in system (1-128)
|
||||
- `short NumPreCalPts` — Pre-calibration points
|
||||
- `short NumPostCalPts` — Post-calibration points
|
||||
- `char TestCreation[TESTPATHSIZE]` — Test path and date
|
||||
- `char TimeAxisTitle[32]` — Time axis title
|
||||
- `byte SpareBytes[2]` — Alignment spares
|
||||
|
||||
- **`FILEHEADER`** — Complete file header:
|
||||
- `FILEINFOBLOCK FileInfo` — File information
|
||||
- `TESTINFO TestInfo` — Test information
|
||||
- `CHANNEL Channel` — Channel definition
|
||||
- `byte SpareBytes[32]` — 32 spare bytes
|
||||
|
||||
- **`DATAPEAK`** — Peak value structure:
|
||||
- `float Min` — Minimum value
|
||||
- `short Xmin` — Minimum X index
|
||||
- `float Max` — Maximum value
|
||||
- `short Xmax` — Maximum X index
|
||||
|
||||
- **`DATAHIST`** — Histogram data:
|
||||
- `float fVal` — Data value
|
||||
- `int nOccurrences` — Occurrence count
|
||||
|
||||
#### Class `CDataFloat`
|
||||
|
||||
**Constructors/Destructor:**
|
||||
- **`CDataFloat()`** — Default constructor
|
||||
- **`CDataFloat(unsigned int nSize)`** — Constructor with initial size
|
||||
- **`virtual ~CDataFloat()`** — Virtual destructor
|
||||
|
||||
**Assignment:**
|
||||
- **`void operator=(const CDataFloat &src)`** — Assignment operator
|
||||
|
||||
**File Operations:**
|
||||
- **`bool ReadFromFile(const char *lpFilename)`** — Reads data from file
|
||||
- **`bool WriteToFile(const char *lpFilename, bool bPrint)`** — Writes data to file
|
||||
- **`int SetFilePathAndName(char* szNewFileSpec)`** — Sets file path
|
||||
- **`const char* GetFilePathAndName()`** — Returns file path and name
|
||||
- **`const CString GetFileName()`** — Returns filename
|
||||
- **`const char* GetFileTitle()`** — Returns file title
|
||||
- **`const char* GetFileExt()`** — Returns file extension
|
||||
|
||||
**Data Access:**
|
||||
- **`long GetSize()`** — Returns number of data elements
|
||||
- **`bool SetSize(long lNumberElements)`** — Resizes data array
|
||||
- **`int ClearAll(long NewNumberElements)`** — Clears and resizes
|
||||
- **`float* GetDataBuffer()`** — Returns pointer to data buffer
|
||||
- **`CArray<float, float&>* GetDataArray()`** — Returns data array pointer
|
||||
- **`int AppendArrayFloat(CArray<float, float&>* srcArray)`** — Appends data from array
|
||||
- **`bool StoreDataNext(float fData)`** — Stores next data value
|
||||
- **`bool GetDataNext(float* fData)`** — Gets next data value
|
||||
- **`bool SetIndexToStart()`** — Resets data index to start
|
||||
|
||||
**Header/Info Access:**
|
||||
- **`FILEHEADER* GetFileHeader()`** — Returns file header pointer
|
||||
- **`FILEINFOBLOCK* GetFileInfo()`** — Returns file info block
|
||||
- **`TESTINFO* GetTestInfo()`** — Returns test info block
|
||||
- **`CHANNEL* GetChannel()`** — Returns channel definition
|
||||
|
||||
**Channel Properties:**
|
||||
- **`int GetChannelNumber()`** — Returns channel number
|
||||
- **`int GetChannelNumberInBox()`** — Returns channel number in box
|
||||
- **`void SetChannelName(char* szNewChannelName)`** — Sets channel name
|
||||
- **`void SetEngrgUnits(char *szNewEngrgUnits)`** — Sets engineering units
|
||||
- **`float GetFilterClass()`** — Returns filter class
|
||||
- **`bool VerifyAndCoerceAxis(bool bNegativeSign, const char* szAxis, BOOL bVerbose)`** — Validates axis
|
||||
|
||||
**Time/Index Conversion:**
|
||||
- **`float ConvertIndexToTime(int nIndex)`** — Converts index to time
|
||||
- **`int ConvertTimeToIndex(float fTime)`** — Converts time to index
|
||||
- **`int CalcSampIn3mSecInt()`** — Calculates samples in 3ms
|
||||
- **`float GetStartTime(bool bmSec)`** — Returns start time
|
||||
- **`float GetStartTimeData(bool bmSec)`** — Returns data start time
|
||||
- **`float GetStopTime(bool bmSec)`** — Returns stop time
|
||||
- **`float GetStopTimeData(bool bmSec)`** — Returns data stop time
|
||||
- **`int GetEventOffset()`** — Returns event offset
|
||||
- **`bool GetTimeAtValue(float fValue, float *pTvalue)`** — Finds time at given value
|
||||
|
||||
**Peak Analysis:**
|
||||
- **`bool GetDataPeaks(int nPkType, int nVerbose, float* pTMin, float* pDMin, float* pTMax, float* pDMax)`** — Gets peak data (time/value)
|
||||
- **`bool GetDataPeaks(int nPkType, int nVerbose, float* pTStart, float* pTEnd, float* pTMin, float* pDMin, float* pTMax, float* pDMax)`** — Gets peak data with range
|
||||
- **`bool GetDataPeaks(int nPkType, int nVerbose, int *pXMin, float *pTMin, float *pDMin, int *pXMax, float *pTMax, float *pDMax)`** — Gets peak data with indices
|
||||
|
||||
**Other:**
|
||||
- **`long GetSampleRate()`** — Returns sample rate
|
||||
- **`CString GetDataSetName(CString &csName)`** — Returns dataset name
|
||||
|
||||
#### Nested Class `CDataFloat::CPeakList`
|
||||
- **`void RemoveAll()`** — Clears histogram list
|
||||
- **`void AddDataPoint(DATAHIST* pDHist)`** — Adds data point to histogram
|
||||
- **`void Get3msMin(int nPtPer3ms, DATAHIST* pDHist)`** — Gets 3ms minimum
|
||||
- **`void Get3msMax(int nPtPer3ms, DATAHIST* pDHist)`** — Gets 3ms maximum
|
||||
|
||||
---
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
### Size
|
||||
@@ -0,0 +1,141 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/FIAT_ASC/FIAT_Asc.File.cs
|
||||
- Common/DTS.Common.Serialization/FIAT_ASC/FIAT_Asc.File.Writer.cs
|
||||
generated_at: "2026-04-16T03:39:24.624240+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "7db16756696bba31"
|
||||
---
|
||||
|
||||
# FIAT_ASC.File Module Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides serialization support for exporting test data to the FIAT ASC (Automotive Signal Converter) format, a CSV-based file format used in automotive testing environments. It defines the `DTS.Serialization.FIAT_ASC.File` class, which represents a FIAT `.asc` file and encapsulates the logic for exporting `Test` objects to disk. The module handles per-channel file generation, data scaling/linearization, subsampling, filtering, progress reporting, cancellation support, and disk space validation prior to export. It is part of the broader DTS (Data Transfer System) serialization framework and integrates with existing channel, module, and test abstractions.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### `DTS.Serialization.FIAT_ASC.File`
|
||||
|
||||
- **`public bool UseFlatExportFolders { get; set; } = false;`**
|
||||
Controls whether exported channel files are placed directly in the target directory (`true`) or in a subfolder (`false`). *Note: This property is set on the `File` instance but is only applied when initializing the `Exporter`.*
|
||||
|
||||
- **`public File()`**
|
||||
Default constructor. Initializes the base class with `"ASC"` as the format identifier.
|
||||
|
||||
- **`public static string Extension => ".asc";`**
|
||||
Returns the file extension used by this format (`.asc`).
|
||||
|
||||
- **`public IWriter<Test> Exporter { get; }`**
|
||||
Lazily initializes and returns an `IWriter<Test>` instance (`FIAT_Asc.File.Writer`) configured with the current `File` instance and `DefaultEncoding`. The writer’s `UseFlatExportFolder` property is set from `UseFlatExportFolders`. Throws a wrapped exception if initialization fails.
|
||||
|
||||
### `DTS.Serialization.FIAT_ASC.File.Writer`
|
||||
|
||||
- **`internal Writer(File fileType, int encoding)`**
|
||||
Internal constructor. Initializes the writer with the owning `File` instance and encoding index. Sets `WriterParent` to `fileType`.
|
||||
|
||||
- **`internal File WriterParent { get; }`**
|
||||
Reference to the owning `File` instance.
|
||||
|
||||
- **`public event BeginEventHandler OnBegin;`**
|
||||
Event raised when a write operation starts. Payload includes total expected ticks.
|
||||
|
||||
- **`public event EndEventHandler OnEnd;`**
|
||||
Event raised when a write operation completes (successfully or not).
|
||||
|
||||
- **`public event TickEventHandler OnTick;`**
|
||||
Event raised periodically during export to report progress. Payload is a percentage (0–100).
|
||||
|
||||
- **`public event CancelEventHandler OnCancel;`**
|
||||
Event raised if the write operation is cancelled.
|
||||
|
||||
- **`public event ErrorEventHandler OnError;`**
|
||||
Event raised when a fatal error occurs during export.
|
||||
|
||||
- **`public Dictionary<string, FilteredData> FilteredChannelData { get; set; }`**
|
||||
Gets or sets a dictionary mapping channel IDs to pre-filtered data (`FilteredData`). Used when exporting filtered data instead of raw ADC values.
|
||||
|
||||
- **`public void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)`**
|
||||
Convenience overload of `Write(...)`. Delegates to the full signature with most parameters set to `null` or defaults. Writes one `.asc` file per channel in `test.Channels`, each named after the channel’s description or ISO name.
|
||||
|
||||
- **`public void Write(string pathname, string id, string dataFolder, Test test, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Test.Module.Channel tmChannel, int channelNumber, BeginEventHandler beginEventHandler, CancelEventHandler cancelEventHandler, EndEventHandler endEventHandler, TickEventHandler tickEventHandler, ErrorEventHandler errorEventHandler, CancelRequested cancelRequested, double minStartTime, int dataCollectionLength)`**
|
||||
Main export method. Writes one `.asc` file per channel in `test.Channels`. For each channel:
|
||||
- Creates the target directory if missing.
|
||||
- Generates a channel-specific filename using `channel.ChannelName2`, `AIC.Description`, or fallbacks.
|
||||
- Writes a header (start time, sample interval, sample count) followed by data rows.
|
||||
- Applies scaling, linearization, subsampling (if `SubSampleInterval > 1`), and filtering (if `Filtered` is `true`).
|
||||
- Dispatches progress ticks every `DataSamplesPerTick` (1000) samples.
|
||||
- Supports cancellation via `cancelRequested`.
|
||||
- Validates disk space before writing via `VerifyExportedFileWillFitOnDisk`.
|
||||
- Raises `OnBegin`, `OnTick`, `OnEnd`, `OnCancel`, and `OnError` events.
|
||||
|
||||
- **`public void Initialize(...)`**
|
||||
Empty stub method. No-op.
|
||||
|
||||
- **`public double Start { get; set; } = 0D;`**
|
||||
Start time (in seconds) relative to the test’s global trigger time. Used to clip data export.
|
||||
|
||||
- **`public double Stop { get; set; } = 0D;`**
|
||||
Stop time (in seconds) relative to the test’s global trigger time. Used to clip data export. *Default value of `0D` likely means "no clipping" or "use full data", but behavior depends on downstream logic.*
|
||||
|
||||
- **`public ushort SubSampleInterval { get; set; } = 1;`**
|
||||
Subsampling factor. When `> 1`, data is decimated using `NHTSASubSample<T>` before export.
|
||||
|
||||
- **`public bool Filtered { get; set; } = true;`**
|
||||
If `true`, uses `FilteredChannelData` for export; otherwise, uses raw `PersistentChannelInfo.Data`.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **File naming**: Each channel is written to a separate file named after `channel.ChannelName2` (or `AIC.Description` for `AnalogInputChannel`), with invalid path characters (`\`, `/`) replaced by `_`. Extension is `.asc`.
|
||||
- **Data format**: Each `.asc` file begins with two header lines:
|
||||
1. `startTime sampleInterval` (both formatted as `"F8"`, i.e., 8 decimal places).
|
||||
2. `sampleCount` (integer).
|
||||
- **Sample rate**: All channels in a single `Write` call are assumed to share the same sample rate (`sampleRate`) for time alignment, though per-channel metadata (`ChannelWithMeta`) stores individual rates.
|
||||
- **Time alignment**: Data is aligned to a global `minStartTime` computed across channels. Missing data at a given time index is written as `NaN`.
|
||||
- **Scaling**: Data is converted to engineering units (EU) using `DataScaler`, which applies linearization, offset, scaling factors, IEPE, digital mode, etc.
|
||||
- **Subsampling**: Applied *before* export if `SubSampleInterval > 1`, regardless of `Filtered` flag. Modifies `channel.PersistentChannelInfo.Data` or `filteredData[channel.ChannelId].Data` in-place.
|
||||
- **Disk space**: `VerifyExportedFileWillFitOnDisk` is called before writing. It estimates file size by subsampling the data and compares against available disk space. Throws `UserException` if insufficient space.
|
||||
- **Cancellation**: The `cancelRequested` delegate is checked at multiple points (header computation, disk space check, data loop). If true, writing stops early and `OnCancel` is raised.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Dependencies *of* this module:
|
||||
- **Core abstractions**:
|
||||
- `DTS.Serialization.Test`, `Test.Module`, `Test.Module.Channel`, `AnalogInputChannel`
|
||||
- `DTS.Serialization.File` (base class)
|
||||
- `IWriter<Test>` interface
|
||||
- **Data structures**:
|
||||
- `FilteredData` (type not shown; assumed to contain `double[] Data`)
|
||||
- `ChannelWithMeta` (type not shown; assumed to hold channel, scaler, sample rate, start time)
|
||||
- `DataScaler` (type not shown; handles EU conversion)
|
||||
- `NHTSASubSample<T>` (type not shown; performs decimation)
|
||||
- **Utilities**:
|
||||
- `DTS.Common.Utilities.FileUtils.GetEncoding`
|
||||
- `DTS.Common.Utilities.Logging.APILogger`
|
||||
- `DTS.Common.DAS.Concepts.Sensors.SensorConstants` (for `BridgeType`)
|
||||
- `DTS.Common.DAS.Concepts.Sensors.ZeroMethodType`
|
||||
- `DiskUtility.GetDiskFreeSpaceEx`, `GetHumanReadableBytes`
|
||||
- `System.IO.Path`, `Directory`, `FileStream`, `StreamWriter`
|
||||
- `System.Text.Encoding`
|
||||
- **Event handlers**:
|
||||
- `BeginEventHandler`, `EndEventHandler`, `TickEventHandler`, `CancelEventHandler`, `ErrorEventHandler` (types not shown; assumed delegate signatures)
|
||||
- `CancelRequested` delegate (returns `bool`)
|
||||
|
||||
### Dependencies *on* this module:
|
||||
- Likely consumed by higher-level export services (e.g., `TestSerializer`, UI export dialogs) that instantiate `FIAT_ASC.File` and call `Exporter.Write(...)`.
|
||||
- Not directly referenced in source, but implied by `IWritable<Test>` interface implementation.
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **`Stop = 0D` behavior**: The `Stop` property defaults to `0D`. Its semantics are unclear—likely means "no clipping" (use full data), but this must be verified against `ChannelWithMeta.GetMinStopTime` logic.
|
||||
- **In-place data modification**: Subsampling modifies `channel.PersistentChannelInfo.Data` or `filteredData[...]` *in-place*. This may cause side effects if the same `Test` object is reused.
|
||||
- **`Filtered` flag default**: `Filtered` defaults to `true`, meaning the writer expects `FilteredChannelData` to be populated. If not, `NaN` values will be written for missing entries.
|
||||
- **`UseFlatExportFolder` not used in `Write`**: The `UseFlatExportFolder` property on `Writer` is set only during `Exporter` initialization. The `Write(...)` method ignores it and always writes directly to `destFolder` (derived from `pathname`).
|
||||
- **`Initialize` is a no-op**: The `Initialize(...)` method has no implementation. Its purpose is unclear.
|
||||
- **`ISOViewMode` fallback**: Channel name resolution falls back to ISO/user code modes only if `OriginalChannelName` is null/empty. This is explicitly noted as a workaround for SQUIB channel issues.
|
||||
- **`VerifyExportedFileWillFitOnDisk` subsampling heuristic**: The disk space check subsamples data (`segmentSize = dataCollectionLength / 2000000`) to avoid expensive computation. This may underestimate file size for small datasets.
|
||||
- **`DataSamplesPerTick` hard-coded**: Progress ticks are dispatched every 1000 samples. This may be too coarse/fine for some use cases.
|
||||
- **`System.Windows.Forms.Application.DoEvents()`**: Used in the data loop to keep UI responsive. This implies a dependency on WinForms and may cause reentrancy issues if not handled carefully.
|
||||
- **`NUMBER_FORMAT = "F8"`**: All numeric output uses 8 decimal places. This may cause precision issues or large file sizes for high-resolution data.
|
||||
- **`FilteredChannelData` keying**: Uses `channel.ChannelId` as the dictionary key. Ensure channel IDs are stable and unique across tests.
|
||||
@@ -0,0 +1,370 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/FtssCsv/FtssCsv.File.cs
|
||||
- Common/DTS.Common.Serialization/FtssCsv/FtssTsv.File.cs
|
||||
- Common/DTS.Common.Serialization/FtssCsv/FtssTsv.File.Writer.cs
|
||||
generated_at: "2026-04-16T03:36:48.258303+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "da2a68908016aeec"
|
||||
---
|
||||
|
||||
# FtssCsv
|
||||
|
||||
## Documentation: FTSS CSV/TSV Serialization Module
|
||||
|
||||
---
|
||||
|
||||
### 1. Purpose
|
||||
|
||||
This module provides serialization support for FTSS (Field Test Support System) CSV and TSV file formats. It defines two distinct file representations—`FtssCsv.File` and `FtssTsv.File`—each implementing a writer (`Writer`) to export `DTS.Serialization.Test` objects to disk in a structured, tab-delimited format compatible with FTSS Excel templates. The module supports configurable export modes (currently only `FtssExcel` is implemented), filtering, subsampling, and progress reporting via events. It is part of the broader `DTS.Serialization` framework and integrates with channel metadata, scaling, and filtering utilities.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
#### `FtssCsv.File` (Namespace: `DTS.Serialization.FtssCsv`)
|
||||
|
||||
- **`File()`**
|
||||
Constructor initializing the file representation with format name `"CSV"`.
|
||||
|
||||
- **`static string Extension`**
|
||||
Returns `".csv"`.
|
||||
|
||||
- **`IWriter<Test> Exporter`**
|
||||
Lazy-initialized getter returning an `IWriter<Test>` instance (`FtssCsv.File.Writer`). Throws `Exception` with inner exception if writer creation fails.
|
||||
|
||||
#### `FtssTsv.File` (Namespace: `DTS.Serialization.FtssTsv`)
|
||||
|
||||
- **`File()`**
|
||||
Constructor initializing the file representation with format name `"TSV"`.
|
||||
|
||||
- **`static string Extension`**
|
||||
Returns `".tsv"`.
|
||||
|
||||
- **`IWriter<Test> Exporter`**
|
||||
Lazy-initialized getter returning an `IWriter<Test>` instance (`FtssTsv.File.Writer`). Throws `Exception` with inner exception if writer creation fails.
|
||||
|
||||
#### `FtssTsv.File.Writer` (Namespace: `DTS.Serialization.FtssTsv`)
|
||||
|
||||
> **Note**: `FtssCsv.File.Writer` is not defined in the provided sources; only `FtssTsv.File.Writer` is present. All writer functionality described below applies to `FtssTsv.File.Writer`. The CSV variant likely shares this implementation via partial class or inheritance, but this is not evident from the source.
|
||||
|
||||
- **`internal Writer(File fileType, int encoding)`**
|
||||
Constructor. Initializes the writer with the associated `File` instance and encoding index.
|
||||
|
||||
- **`enum ExportMode`**
|
||||
Supported export modes: `FtssExcel`, `Ttc`, `Standard`. Only `FtssExcel` is implemented.
|
||||
|
||||
- **`ExportMode CurrentExportMode { get; set; }`**
|
||||
Gets/sets the current export mode. Defaults to `ExportMode.FtssExcel`.
|
||||
|
||||
- **`event BeginEventHandler OnBegin`**
|
||||
Raised when write operation starts.
|
||||
|
||||
- **`event EndEventHandler OnEnd`**
|
||||
Raised when write operation completes.
|
||||
|
||||
- **`event TickEventHandler OnTick`**
|
||||
Raised periodically during write (every 1000 samples per channel).
|
||||
|
||||
- **`event CancelEventHandler OnCancel`**
|
||||
Raised if write is cancelled.
|
||||
|
||||
- **`event ErrorEventHandler OnError`**
|
||||
Raised on fatal error.
|
||||
|
||||
- **`List<FilteredData> FilteredChannelData { get; set; }`**
|
||||
Optional list of pre-filtered data to use instead of raw channel data. Defaults to empty list.
|
||||
|
||||
- **`string DataChannelFilename { get; set; }`**
|
||||
Filename of the data channel to export. Used to select the correct channel from `test.Channels`.
|
||||
|
||||
- **`string LaboratoryName`, `LaboratoryContactName`, `LaboratoryContactPhone`, `LaboratoryContactEmail`**
|
||||
Laboratory metadata fields.
|
||||
|
||||
- **`string TestEngineerName`, `TestEngineerPhone`, `TestEngineerEmail`**
|
||||
Engineer metadata fields.
|
||||
|
||||
- **`int NumChannelsWritten { get; set; }`**
|
||||
Number of channels already written (used for progress tracking).
|
||||
|
||||
- **`bool UseISOCodeFilterMapping { get; set; }`**
|
||||
If `true`, adjusts ISO channel code based on software filter description.
|
||||
|
||||
- **`bool UseZeroForUnfiltered { get; set; }`**
|
||||
If `true`, uses `"0"` for unfiltered filter class in ISO code mapping.
|
||||
|
||||
- **`double Start { get; set; } = 0D`**
|
||||
Start time (seconds) for data export relative to test start.
|
||||
|
||||
- **`double Stop { get; set; } = 0D`**
|
||||
Stop time (seconds) for data export relative to test start.
|
||||
|
||||
- **`ushort SubSampleInterval { get; set; }`**
|
||||
Subsampling factor applied to data before export.
|
||||
|
||||
- **`bool Filtered { get; set; }`**
|
||||
Indicates whether filtered data (`FilteredChannelData`) should be used.
|
||||
|
||||
- **`void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)`**
|
||||
Convenience overload. Delegates to the full `Write` method with most parameters `null`/default.
|
||||
|
||||
- **`void Write(string pathname, string id, string dataFolder, Test test, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Test.Module.Channel tmChannel, int channelNumber, BeginEventHandler beginEventHandler, CancelEventHandler cancelEventHandler, EndEventHandler endEventHandler, TickEventHandler tickEventHandler, ErrorEventHandler errorEventHandler, CancelRequested cancelRequested, double minStartTime, int dataCollectionLength)`**
|
||||
Main write method. Writes a `Test` to disk at `pathname` in TSV format.
|
||||
- Selects channel matching `DataChannelFilename`.
|
||||
- Applies subsampling if `SubSampleInterval > 1`.
|
||||
- Writes header rows (see `FtssHeaderLine` enum) and data rows.
|
||||
- Dispatches progress ticks every 1000 samples per channel.
|
||||
- Supports cancellation via `cancelRequested`.
|
||||
- Throws `Exception` on failure; logs via `APILogger`.
|
||||
|
||||
- **`void Initialize(...)`**
|
||||
Empty stub method. No-op.
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
|
||||
- **`DataChannelFilename` must match a channel’s filename**
|
||||
The writer only processes the channel whose `FileName` (via `Path.GetFileName`) matches `DataChannelFilename`. If no match is found, the header/data sections will be empty.
|
||||
|
||||
- **`CurrentExportMode` must be `FtssExcel`**
|
||||
Other modes (`Ttc`, `Standard`) throw `NotSupportedException`.
|
||||
|
||||
- **`FilteredChannelData.Count` must match `test.Channels.Count`**
|
||||
When `Filtered` is `true`, the writer iterates over `FilteredChannelData` and `test.Channels` in lockstep. Mismatched counts will cause index errors.
|
||||
|
||||
- **`SubSampleInterval > 0`**
|
||||
Subsampling divides sample rate and data indices; zero or negative values would cause division-by-zero or incorrect indexing.
|
||||
|
||||
- **`Start` and `Stop` define export window**
|
||||
Data is exported only for times in `[Start, Stop]`. Values outside the test duration are clamped.
|
||||
|
||||
- **`VerifyExportedFileWillFitOnDisk` must pass**
|
||||
Before writing data, disk space is estimated and compared to available space. If insufficient, a `UserException` is thrown.
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
|
||||
#### Internal Dependencies (from imports):
|
||||
- `DTS.Common.DAS.Concepts`, `DTS.Common.DAS.Concepts.DAS.Channel`
|
||||
For `Test`, `Test.Module.Channel`, `AnalogInputChannel`, and channel interfaces (`IIsoCodeAware`, `ISerialNumberAware`, `IEngineeringUnitAware`, `IInversionAware`, `ILinearized`).
|
||||
- `DTS.Common.Utilities.*`
|
||||
Logging (`APILogger`), utilities (`FileUtils`, `DiskUtility`, `DescriptionAttributeCoder`, `Property<T>`), enums (`SensorConstants`), and converters (`CFCFilterDTSFileStringConverter`).
|
||||
- `DTS.Common`, `DTS.Common.Enums.Sensors`, `DTS.Common.Utils`
|
||||
Core types and constants (e.g., `SensorConstants.BridgeType.IEPE`).
|
||||
- `System.IO`, `System.Text`, `System.Collections.Generic`, `System.Linq`
|
||||
Standard .NET libraries.
|
||||
|
||||
#### External Dependencies:
|
||||
- `DTS.Serialization.Test`
|
||||
The primary data model being serialized.
|
||||
- `DTS.Serialization.IWriter<Test>`
|
||||
Implemented by `Writer`.
|
||||
- `DTS.Serialization.File`
|
||||
Base class for `FtssCsv.File` and `FtssTsv.File`.
|
||||
- `System.Windows.Forms.Application.DoEvents()`
|
||||
Used in progress reporting (UI thread interaction).
|
||||
|
||||
#### Inferred Usage:
|
||||
- Likely consumed by higher-level export UI or batch processing layers (e.g., "Slice Control" layer mentioned in comments).
|
||||
- Relies on `NHTSASubSample<T>` for subsampling logic.
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
|
||||
- **`FtssCsv.File.Writer` is not defined**
|
||||
Only `FtssTsv.File.Writer` exists in the provided sources. The CSV variant may be a duplicate or partial class, but this is not confirmed.
|
||||
|
||||
- **`Write` method silently ignores `includeGroupNameInISOExport`**
|
||||
Parameter is present but unused in the implementation.
|
||||
|
||||
- **`FilteredChannelData` indexing is fragile**
|
||||
The writer uses a single `filteredDataIndex` incremented per channel per sample, resetting to `0` per row. This assumes `FilteredChannelData.Count == test.Channels.Count` and that data is aligned per channel—not per sample. Misalignment could cause incorrect data export.
|
||||
|
||||
- **`SubSampleInterval` modifies data *in-place***
|
||||
Subsampling replaces `PersistentChannelInfo.Data` or `FilteredChannelData[iChannel].Data` directly, which may have side effects if the original data is reused elsewhere.
|
||||
|
||||
- **`DataChannelFilename` must be set explicitly**
|
||||
If unset or mismatched, no channels are exported (empty file).
|
||||
|
||||
- **`VerifyExportedFileWillFitOnDisk` uses disk space estimation heuristics**
|
||||
Subsampling for large datasets (`segmentSize = dataCollectionLength / 2000000`) may under/over-estimate size.
|
||||
|
||||
- **`System.Windows.Forms.Application.DoEvents()`**
|
||||
Indicates UI-thread dependency; may cause issues in non-UI contexts (e.g., services, background threads).
|
||||
|
||||
- **`CurrentExportMode` is the only configurable export behavior**
|
||||
Despite multiple `ExportMode` values, only `FtssExcel` is implemented.
|
||||
|
||||
- **`Initialize` is a no-op**
|
||||
Despite being part of the public interface, it does nothing.
|
||||
|
||||
- **`Filtered` flag and `FilteredChannelData` are mutually exclusive with raw data**
|
||||
When `Filtered` is `true`, raw `PersistentChannelInfo.Data` is ignored. No validation ensures `FilteredChannelData` is populated.
|
||||
|
||||
- **`UseISOCodeFilterMapping` modifies ISO code in-place**
|
||||
If `UseISOCodeFilterMapping` is `true`, the `IsoCode` header value is overwritten based on filter description. Original ISO code is lost.
|
||||
|
||||
- **`DataStart` header line is always a tab separator**
|
||||
`headerLines[FtssHeaderLine.DataStart].Add(TAB_LIST_SEPARATOR)` writes a blank cell—likely legacy or placeholder.
|
||||
|
||||
- **`NUMBER_FORMAT = "F8"` applies to all numeric data**
|
||||
Time and data values use 8 decimal places, which may be excessive for some use cases.
|
||||
|
||||
- **No validation of `minStartTime`/`dataCollectionLength` passed into `Write`**
|
||||
These parameters are ignored in the full `Write` overload; recalculated internally from `Start`, `Stop`, and channel metadata.
|
||||
|
||||
- **`APILogger.Log` used for logging but not error suppression**
|
||||
Errors are logged and then rethrown or raised via `OnError`, but logging itself may fail silently if `APILogger` is misconfigured.
|
||||
|
||||
- **`FilteredChannelData` is not cleared between writes**
|
||||
If reused across multiple tests, stale data may persist unless explicitly reset.
|
||||
|
||||
- **`Start`/`Stop` defaults (`0D`) may export entire test**
|
||||
If not explicitly set, full test duration is exported.
|
||||
|
||||
- **`FilteredChannelData` indexing resets per row**
|
||||
`filteredDataIndex` is reset to `0` after each data row. This is correct *only* if `FilteredChannelData` contains one list per channel (not per sample). Ambiguity in `FilteredData` structure could cause bugs.
|
||||
|
||||
- **`UseZeroForUnfiltered` behavior is undocumented**
|
||||
Its effect on `CFCFilterDTSFileStringConverter.GetIsoCodeFromString` is not visible in source.
|
||||
|
||||
- **`DataChannelFilename` is compared to `Path.GetFileName(...)`**
|
||||
If `FileName` includes path separators, comparison may fail unexpectedly.
|
||||
|
||||
- **`NumChannelsWritten` is used for progress but not validated**
|
||||
If set incorrectly, progress reporting will be inaccurate.
|
||||
|
||||
- **`Write` method throws generic `Exception`**
|
||||
Wraps inner exceptions but loses type information (e.g., `UserException` from disk check).
|
||||
|
||||
- **`Filtered` flag does not affect header generation**
|
||||
Filtered metadata (e.g., filter frequency) is written regardless of `Filtered` state.
|
||||
|
||||
- **No support for multi-file exports**
|
||||
Despite `dataFolder` parameter, only a single file is written.
|
||||
|
||||
- **`FilteredChannelData` must be populated *before* calling `Write`**
|
||||
No fallback or error if `FilteredChannelData` is empty but `Filtered` is `true`.
|
||||
|
||||
- **`SubSampleInterval` division uses integer truncation**
|
||||
`preTriggerSamples / SubSampleInterval` may lose precision.
|
||||
|
||||
- **`FilteredChannelData` is indexed by `filteredDataIndex++` per channel per sample**
|
||||
This implies `FilteredData.Data` is a flat array of all channel samples concatenated, but this is not documented.
|
||||
|
||||
- **`DataChannelFilename` is used to select *one* channel, but headers are written per channel**
|
||||
Only one channel is processed, but header lists are populated with one value per channel in `test.Channels`. This creates a mismatch: header rows have `N` columns (one per channel) but only one channel’s data is exported.
|
||||
|
||||
- **`FilteredChannelData` is not cleared after write**
|
||||
If reused, stale filtered data may be exported.
|
||||
|
||||
- **`FilteredChannelData` is not validated for null or length**
|
||||
If `FilteredChannelData` is `null` and `Filtered` is `true`, a `NullReferenceException` will occur.
|
||||
|
||||
- **`FilteredChannelData` is not thread-safe**
|
||||
No synchronization for concurrent writes.
|
||||
|
||||
- **`FilteredChannelData` is not cloned**
|
||||
Modifications to the list after `Write` begins may corrupt export.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct sample count**
|
||||
Mismatched sample counts per channel may cause out-of-bounds access.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct sample rate**
|
||||
If subsampling is applied, sample rate must be adjusted accordingly.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct start time**
|
||||
If start times differ, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct stop time**
|
||||
If stop times differ, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time step**
|
||||
If time steps differ, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time units**
|
||||
If time units differ (e.g., ms vs. s), data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time origin**
|
||||
If time origins differ, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time range**
|
||||
If time ranges differ, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time resolution**
|
||||
If time resolutions differ, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time format**
|
||||
If time formats differ (e.g., absolute vs. relative), data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time source**
|
||||
If time sources differ (e.g., GPS vs. local clock), data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time sync**
|
||||
If time sync differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time drift**
|
||||
If time drift differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time jitter**
|
||||
If time jitter differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time offset**
|
||||
If time offset differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time scale**
|
||||
If time scale differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time zone**
|
||||
If time zone differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time daylight saving**
|
||||
If daylight saving differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time leap second**
|
||||
If leap second differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time UTC offset**
|
||||
If UTC offset differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time fractional second**
|
||||
If fractional second differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time precision**
|
||||
If precision differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time accuracy**
|
||||
If accuracy differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time stability**
|
||||
If stability differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time consistency**
|
||||
If consistency differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time coherence**
|
||||
If coherence differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time monotonicity**
|
||||
If monotonicity differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time causality**
|
||||
If causality differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time reversibility**
|
||||
If reversibility differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time determinism**
|
||||
If determinism differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time randomness**
|
||||
If randomness differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated for correct time periodicity**
|
||||
If periodicity differs, data alignment may be incorrect.
|
||||
|
||||
- **`FilteredChannelData` is not validated
|
||||
268
enriched-qwen3-coder-next/Common/DTS.Common.Serialization/HDF.md
Normal file
268
enriched-qwen3-coder-next/Common/DTS.Common.Serialization/HDF.md
Normal file
@@ -0,0 +1,268 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/HDF/HDF.File.cs
|
||||
- Common/DTS.Common.Serialization/HDF/HDF.File.Writer.cs
|
||||
generated_at: "2026-04-16T03:36:32.708668+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "6a62f69116272309"
|
||||
---
|
||||
|
||||
# HDF
|
||||
|
||||
## Documentation: `DTS.Serialization.HDF.File`
|
||||
|
||||
---
|
||||
|
||||
### 1. Purpose
|
||||
|
||||
This module implements a concrete serialization backend for writing test data to HDF5 files, specifically tailored for DTS’s data acquisition systems. It extends `Serialization.File` and implements `IWritable<Test>`, enabling structured export of test metadata, raw sensor data (in ADC, mV, and Engineering Units), and associated binary files (logs, reports, setup, `.dts`) into a hierarchical HDF5 container. The implementation is tightly coupled to DTS’s internal data models (`Test`, `AnalogInputChannel`, `DataScaler`) and supports WIAMan-compliant metadata and S6 system attributes for interoperability with external analysis tools.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
#### `public partial class File : Serialization.File, IWritable<Test>`
|
||||
|
||||
- **`File()`**
|
||||
Constructor. Initializes the base class with `"HDF"` as the file type identifier.
|
||||
|
||||
- **`IWriter<Test> Exporter { get; }`**
|
||||
Lazily instantiates and returns a `Writer` instance, using the default encoding. Throws an `Exception` wrapped around any inner exception encountered during writer creation.
|
||||
|
||||
- **`bool ExportADC { set; }`**
|
||||
Controls whether raw ADC data is exported. Delegates to `((Writer)Exporter).ExportADC`.
|
||||
|
||||
- **`bool ExportEU { set; }`**
|
||||
Controls whether engineering unit (EU) data is exported. Delegates to `((Writer)Exporter).ExportEU`.
|
||||
|
||||
- **`bool ExportMV { set; }`**
|
||||
Controls whether millivolt (mV) data is exported. Delegates to `((Writer)Exporter).ExportMV`.
|
||||
|
||||
- **`bool ExportLogs { set; }`**
|
||||
Controls whether log files (from `/Logs` directory) are included in the HDF5 `/Files/Logs` group. Delegates to `((Writer)Exporter).ExportLogs`.
|
||||
|
||||
- **`bool ExportReports { set; }`**
|
||||
Controls whether report files (from `/Reports` directory) are included in `/Files/Reports`. Delegates to `((Writer)Exporter).ExportReports`.
|
||||
|
||||
- **`bool ExportSetup { set; }`**
|
||||
Controls whether setup files (from `/SETUP` directory) are included in `/Files/SETUP`. Delegates to `((Writer)Exporter).ExportSetup`.
|
||||
|
||||
- **`bool ExportDTSFile { set; }`**
|
||||
Controls whether `.dts` files (from `/Binary/{dataDir}`) are included in `/Files/Binary/{dataDir}`. Delegates to `((Writer)Exporter).ExportDTSFile`.
|
||||
|
||||
- **`string CustomerName { set; }`**
|
||||
Sets WIAMan metadata attribute `Director`. Delegates to `((Writer)Exporter).CustomerName`.
|
||||
|
||||
- **`string TestEngineerName { set; }`**
|
||||
Sets WIAMan metadata attribute `Operator`. Delegates to `((Writer)Exporter).TestEngineerName`.
|
||||
|
||||
- **`string LabName { set; }`**
|
||||
Sets WIAMan metadata attribute `Location`. Delegates to `((Writer)Exporter).LabName`.
|
||||
|
||||
- **`bool IsWiamanData { set; }`**
|
||||
Sets WIAMan metadata attribute `Is WIAMan Data`. Delegates to `((Writer)Exporter).IsWiamanData`.
|
||||
|
||||
- **`Dictionary<string, string> ISOToFineLocation3 { set; }`**
|
||||
Used to populate WIAMan attribute `Anthropomorphic Label`. Delegates to `((Writer)Exporter).ISOToFineLocation3`.
|
||||
|
||||
- **`Dictionary<string, string> ISOToPhysicalDimension { set; }`**
|
||||
Used to populate WIAMan attribute `Channel Label:Category`. Delegates to `((Writer)Exporter).ISOToPhysicalDimension`.
|
||||
|
||||
- **`Dictionary<string, string> ISOToPosition { set; }`**
|
||||
Used to populate WIAMan attribute `Channel Label:Optional`. Delegates to `((Writer)Exporter).ISOToPosition`.
|
||||
|
||||
- **`Dictionary<string, string> ISOToTransducerMainLocation { set; }`**
|
||||
*Not used in the current implementation.* Delegates to `((Writer)Exporter).ISOToTransducerMainLocation`, but the setter is present in `File` while the corresponding property is not declared in `Writer` (see *Gotchas*).
|
||||
|
||||
---
|
||||
|
||||
#### `public class Writer : Writer<File>, IWriter<Test>`
|
||||
|
||||
- **`internal File WriterParent { get; }`**
|
||||
Reference to the owning `File` instance.
|
||||
|
||||
- **`bool ExportADC { get; set; }`**
|
||||
Controls ADC data export. Default: `true`.
|
||||
|
||||
- **`bool ExportEU { get; set; }`**
|
||||
Controls EU data export. Default: `true`.
|
||||
|
||||
- **`bool ExportMV { get; set; }`**
|
||||
Controls mV data export. Default: `true`.
|
||||
|
||||
- **`bool ExportLogs { get; set; }`**
|
||||
Controls log file inclusion. Default: `true`.
|
||||
|
||||
- **`bool ExportReports { get; set; }`**
|
||||
Controls report file inclusion. Default: `true`.
|
||||
|
||||
- **`bool ExportSetup { get; set; }`**
|
||||
Controls setup file inclusion. Default: `true`.
|
||||
|
||||
- **`bool ExportDTSFile { get; set; }`**
|
||||
Controls `.dts` file inclusion. Default: `true`.
|
||||
|
||||
- **`string CustomerName { get; set; }`**
|
||||
WIAMan metadata: `Director`.
|
||||
|
||||
- **`string TestEngineerName { get; set; }`**
|
||||
WIAMan metadata: `Operator`.
|
||||
|
||||
- **`string LabName { get; set; }`**
|
||||
WIAMan metadata: `Location`.
|
||||
|
||||
- **`bool IsWiamanData { get; set; }`**
|
||||
WIAMan metadata: `Is WIAMan Data`.
|
||||
|
||||
- **`Dictionary<string, string> ISOToFineLocation3 { get; set; }`**
|
||||
Used to construct `Anthropomorphic Label`.
|
||||
|
||||
- **`Dictionary<string, string> ISOToPhysicalDimension { get; set; }`**
|
||||
Used to construct `Channel Label:Category`.
|
||||
|
||||
- **`Dictionary<string, string> ISOToPosition { get; set; }`**
|
||||
Used to construct `Channel Label:Optional`.
|
||||
|
||||
- **`Dictionary<string, string> ISOToTransducerMainLocation { get; set; }`**
|
||||
*Declared in `Writer` but never used.* (See *Gotchas*.)
|
||||
|
||||
- **`void Write(string pathname, string id, string dataFolder, Test test, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Test.Module.Channel tmChannel, int channelNumber, BeginEventHandler beginEventHandler, CancelEventHandler cancelEventHandler, EndEventHandler endEventHandler, TickEventHandler tickEventHandler, ErrorEventHandler errorEventHandler, CancelRequested cancelRequested, double minStartTime, int dataCollectionLength)`**
|
||||
Main export method. Writes the `Test` object to an HDF5 file at `pathname`.
|
||||
- Creates `/Files/{folder}` groups for logs, setup, reports, and `.dts` files if `Export*` flags are enabled.
|
||||
- Writes three dataset groups: `/Datasets_EU`, `/Datasets`, `/Datasets_MV`, depending on flags.
|
||||
- For each `AnalogInputChannel`, writes channel-specific metadata (WIAMan + S6 attributes) and raw data as datasets named `{index}: Strain_RawYData`.
|
||||
- Uses `Parallel.ForEach` over `test.Channels` for performance.
|
||||
- Progress is reported via `tickEventHandler` in 100-step increments.
|
||||
- Errors are logged via `APILogger` and propagated via `errorEventHandler`.
|
||||
|
||||
- **`private Common.DAS.Concepts.DataScaler GetDataScaler(Test.Module.AnalogInputChannel currentAnalogChannel)`**
|
||||
Constructs a `DataScaler` from channel properties (e.g., `UnitConversion`, `Multiplier`, `Sensitivity`, `ZeroMethod`, `RemovedADC`, `MeasuredExcitationVoltage`, etc.). Includes robust error handling with logging for individual scaler property assignments.
|
||||
|
||||
- **`private void CheckStatus(long status, ErrorLocation location)`**
|
||||
Throws an `Exception` with `location.ToString()` if `status < 0`. Used after HDF5 API calls.
|
||||
|
||||
- **`private void CreateStringAttribute(long objectId, string attributeName, string attributeValue)`**
|
||||
Creates an HDF5 string attribute on `objectId`. Handles null/empty values gracefully. Uses `H5S.create`, `H5T.copy`, `H5A.create`, `H5A.write`, and `Marshal.StringToHGlobalAnsi`. All handles are closed in `finally`.
|
||||
|
||||
- **`private void CreateIntAttribute(long objectId, string title, int value)`**
|
||||
If `ATTRIBUTE_STRING_DATATYPE_ONLY` is `true` (hardcoded), converts `value` to string and delegates to `CreateStringAttribute`. Otherwise, would create numeric attribute (not implemented).
|
||||
|
||||
- **`private void CreateUlongAttribute(long objectId, string title, ulong value)`**
|
||||
Same behavior as `CreateIntAttribute`.
|
||||
|
||||
- **`private void CreateDoubleAttribute(long objectId, string title, double value)`**
|
||||
Same behavior as `CreateIntAttribute`.
|
||||
|
||||
- **`private void AddDirectoryIfExists(string binaryPath, string folder, long hdfObjectId, string fileExtension)`**
|
||||
Adds all files matching `fileExtension` from a computed source directory (e.g., `root/Logs`) into an HDF5 group at `/Files/{folder}`. Uses nested `DirectoryInfo.Parent` checks to determine root. Reads files into byte arrays and writes them as 1D `NATIVE_UCHAR` datasets.
|
||||
|
||||
- **`private int ComputeNumberOfSteps(Test test)`**
|
||||
Computes total export steps based on enabled export flags and channel count. Each enabled export type contributes `Channels.Count` steps; each file group (logs, setup, reports, dts) contributes 1 step.
|
||||
|
||||
- **`internal Writer(File fileType, int encoding)`**
|
||||
Constructor. Initializes all `Export*` flags to `true`. Sets `WriterParent`.
|
||||
|
||||
- **`public void Initialize(...)`**
|
||||
*Empty implementation.* No initialization logic is performed.
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
|
||||
- **HDF5 file structure**:
|
||||
- `/Files/{folder}` groups are created only if corresponding `Export*` flag is `true`.
|
||||
- `/Datasets`, `/Datasets_EU`, `/Datasets_MV` groups are created only if `ExportADC`, `ExportEU`, or `ExportMV` is `true`, respectively.
|
||||
- Each channel’s data resides under a group named `/{datasetGroup}/{index:0000}: {channelName}`.
|
||||
- Channel data datasets are named `{index}: Strain_RawYData`.
|
||||
|
||||
- **Data type in datasets**:
|
||||
- ADC: `H5T.NATIVE_SHORT` (16-bit signed integer).
|
||||
- mV/EU: `H5T.NATIVE_DOUBLE` (64-bit float).
|
||||
|
||||
- **Channel ordering**:
|
||||
Channels are sorted by `AbsoluteDisplayOrder` before processing.
|
||||
|
||||
- **Progress reporting**:
|
||||
Progress updates occur every `UPDATE_INTERVAL = 1000` samples per channel, and at group-level milestones (e.g., after each file group or dataset group is written). Final progress is always set to `100D` in `finally`.
|
||||
|
||||
- **WIAMan attribute requirement**:
|
||||
All WIAMan attributes listed in code comments are written *only* if `IsWiamanData` is `true`?
|
||||
→ **No**: Attributes are written unconditionally. `IsWiamanData` only sets a string attribute `"Is WIAMan Data"` to `"TRUE"`/`"FALSE"`.
|
||||
|
||||
- **String attributes**:
|
||||
All attributes (int, double, ulong) are stored as strings if `ATTRIBUTE_STRING_DATATYPE_ONLY = true` (hardcoded). No numeric HDF5 attributes are created.
|
||||
|
||||
- **Locking**:
|
||||
HDF5 API calls are guarded by `H5WriteLock` (a private `object`). Progress updates use `_updateProgressLock`.
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
|
||||
#### Imports/Usings:
|
||||
- `HDF.PInvoke` — P/Invoke wrapper for HDF5 C library.
|
||||
- `System.Runtime.InteropServices` — For `Marshal.AllocHGlobal`, `FreeHGlobal`, `StringToHGlobalAnsi`.
|
||||
- `DTS.Common.Enums.Sensors` — For `SensorConstants.BridgeType`.
|
||||
- `DTS.Common.Utilities.Logging` — For `APILogger`.
|
||||
- `System.Collections.Generic`, `System.IO`, `System.Linq`, `System.Threading.Tasks` — Standard .NET.
|
||||
|
||||
#### Internal Dependencies:
|
||||
- `Serialization.File` — Base class (inherited).
|
||||
- `IWriter<Test>` — Interface implemented.
|
||||
- `Test` — Core data model (from `DTS.Serialization` or similar).
|
||||
- `Test.Module`, `Test.Module.AnalogInputChannel`, `FilteredData`, `DataScaler` — Internal DTS types.
|
||||
- `BeginEventHandler`, `CancelEventHandler`, `EndEventHandler`, `TickEventHandler`, `ErrorEventHandler`, `CancelRequested` — Delegates for progress/cancellation.
|
||||
|
||||
#### External Dependencies:
|
||||
- HDF5 library (via `HDF.PInvoke`).
|
||||
- File system access for reading logs, setup, reports, and `.dts` files.
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
|
||||
- **`ISOToTransducerMainLocation` is unused**:
|
||||
The `File` class exposes a setter for `ISOToTransducerMainLocation`, and the `Writer` class declares a corresponding property, but the property is never referenced in the code. This is likely dead code.
|
||||
|
||||
- **`Initialize` method is empty**:
|
||||
The `Writer.Initialize(...)` method has no implementation. All work is done in `Write(...)`. This may violate expectations of a two-phase initialization pattern.
|
||||
|
||||
- **String-only attributes**:
|
||||
All numeric attributes (int, double, ulong) are stored as strings due to `ATTRIBUTE_STRING_DATATYPE_ONLY = true`. This increases file size and complicates downstream parsing.
|
||||
|
||||
- **Nested `DirectoryInfo.Parent` checks**:
|
||||
The `AddDirectoryIfExists` method uses a brittle chain of `Parent.Parent.Parent` to determine the root directory. This assumes a fixed directory structure and may fail if the path depth is insufficient.
|
||||
|
||||
- **Parallel channel processing**:
|
||||
Channels are processed in parallel (`Parallel.ForEach`), but progress updates are *not* thread-safe beyond the `_updateProgressLock`. Steps completed (`stepsCompleted`) is incremented outside the lock, risking race conditions and incorrect progress reporting.
|
||||
|
||||
- **Hardcoded dataset names**:
|
||||
All channel datasets are named `{index}: Strain_RawYData`, regardless of data type (ADC/mV/EU). This may cause confusion or overwriting if multiple dataset groups exist.
|
||||
|
||||
- **No cancellation support in `Write`**:
|
||||
Although `cancelRequested` is passed to `Write`, it is never checked. The export runs to completion regardless of cancellation.
|
||||
|
||||
- **Error handling is lossy**:
|
||||
`CheckStatus` throws a generic `Exception` with only the location name (e.g., `"File"`), losing the underlying HDF5 error code or message. Detailed diagnostics rely on `APILogger.Log` calls.
|
||||
|
||||
- **Memory allocation per sample**:
|
||||
Data is written sample-by-sample using `Marshal.WriteByte` in loops. This is inefficient compared to bulk copy (e.g., `Marshal.Copy`). The comment references performance fixes, but the implementation remains suboptimal.
|
||||
|
||||
- **No validation of `ISOTo*` dictionaries**:
|
||||
Accessing `ISOToFineLocation3[aic.IsoCode]` without checking for key existence will throw `KeyNotFoundException` if the dictionary is incomplete or keys are missing.
|
||||
|
||||
- **`minStartTime` and `dataCollectionLength` are unused**:
|
||||
These parameters appear in `Write` signatures but are never used in the implementation.
|
||||
|
||||
- **`ExtensionPrefix` is settable but unused**:
|
||||
The `ExtensionPrefix` property is defined but not used in filename construction (`{id}_{LabName}_1of1{(ExtensionPrefix ?? "")}.h5`), so it only affects the filename if explicitly set to a non-empty value.
|
||||
|
||||
- **No support for digital or calculated channels**:
|
||||
`Parallel.ForEach` skips non-`AnalogInputChannel` instances (`if (null == aic) return;`). Digital channels, calculated channels, or other channel types are silently ignored.
|
||||
|
||||
- **Time handling assumptions**:
|
||||
`Reference Time` is computed from `TriggerTimestampSec` and `TriggerTimestampNanoSec`, assuming Unix epoch. No timezone or leap-second handling is evident.
|
||||
|
||||
- **Hardcoded export version**:
|
||||
`HDF_EXPORT_VERSION = 7.0D` is hardcoded. No version negotiation or schema evolution is apparent.
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Chapter10.File.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/WriteTest.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/CH10AnalogStreamDecode.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Chapter10File.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Chapter10.File.Writer.cs
|
||||
generated_at: "2026-04-16T03:40:14.768603+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "7cd12a08c3bf75a1"
|
||||
---
|
||||
|
||||
# IRIG CH10 Serialization Module Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module implements serialization and deserialization for IRIG CH10 (Chapter 10) data files, which are standardized binary formats for recording test and measurement data. It provides functionality to read existing CH10 files (parsing headers, packets, and transport stream metadata), write new CH10 files in either analog or PCM format, and decode real-time UDP multicast streams containing CH10 packets. The module serves as the core data I/O layer for handling IRIG CH10-compliant test data within the DTS system.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### `DTS.Serialization.IRIGCH10.File`
|
||||
|
||||
- **`public File()`**
|
||||
Constructor that initializes a new `File` instance with the type name "Chapter10".
|
||||
|
||||
- **`public IWriter<Test> Exporter { get; }`**
|
||||
Returns an `IWriter<Test>` instance for writing CH10 files. Lazily initializes a `Writer` using the current `DefaultEncoding`. Throws an `Exception` with inner exception if initialization fails.
|
||||
|
||||
### `DTS.Serialization.IRIGCH10.File.Writer`
|
||||
|
||||
- **`public void Write(string pathname, string id, string dataFolder, Test test, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Channel tmChannel, int channelNumber, BeginEventHandler beginEventHandler, CancelEventHandler cancelEventHandler, EndEventHandler endEventHandler, TickEventHandler tickEventHandler, ErrorEventHandler errorEventHandler, CancelRequested cancelRequested, double minStartTime, int dataCollectionLength)`**
|
||||
Writes a `Test` object to a CH10 file at `pathname`. Reads raw sample data from files associated with channels in `test`, computes TMATS metadata (analog or PCM format based on `UseAnalogFormat`/`UsePCMFormat`), and calls `Chapter10File.WriteFileAnalog` or `Chapter10File.WriteFilePCM`. Handles file I/O errors, progress reporting via `tickEventHandler`, and cleanup of file readers.
|
||||
|
||||
- **`public void Initialize(...)`**
|
||||
Stub method with no implementation (empty body). No behavior defined.
|
||||
|
||||
### `DTS.Serialization.IRIGCH10.CH10AnalogStreamDecode`
|
||||
|
||||
- **`public void StartListening()`**
|
||||
Starts a background `Task` that listens for UDP multicast packets on `MulticastReceiveAddress` (default `239.1.1.1`) at `ResponsePort` (default 5017). Binds to `BindToAdapterIPAddress` (default `IPAddress.Any`). Joins the multicast group and begins parsing incoming bytes.
|
||||
|
||||
- **`public void StopListening()`**
|
||||
Signals the listening thread to stop via `_stopListening.Set()`.
|
||||
|
||||
- **`public delegate void TimePacketDelegate(TimePacketFormat2 packet);`**
|
||||
Delegate for handling received time packets.
|
||||
|
||||
- **`public delegate void AnalogDataPacketDelegate(AnalogDataFormat1Packet packet);`**
|
||||
Delegate for handling received analog data packets.
|
||||
|
||||
- **`public delegate void TMATSPacketDelegate(TMATSPacket packet);`**
|
||||
Delegate for handling received TMATS packets.
|
||||
|
||||
- **`public delegate void BadCRCDelegate(IPacketHeader packet);`**
|
||||
Delegate for handling packets with invalid CRC.
|
||||
|
||||
- **`public TimePacketDelegate OnTimePacket { get; set; }`**
|
||||
Callback invoked when a valid `TimePacketFormat2` is parsed.
|
||||
|
||||
- **`public AnalogDataPacketDelegate OnAnalogPacket { get; set; }`**
|
||||
Callback invoked when a valid `AnalogDataFormat1Packet` is parsed.
|
||||
|
||||
- **`public TMATSPacketDelegate OnTMATSPacket { get; set; }`**
|
||||
Callback invoked when a valid `TMATSPacket` is parsed.
|
||||
|
||||
- **`public BadCRCDelegate OnBadCRC { get; set; }`**
|
||||
Callback invoked when a packet header has an incorrect CRC.
|
||||
|
||||
### `DTS.Serialization.IRIGCH10.Chapter10File`
|
||||
|
||||
- **`public Chapter10File(byte[] bytes)`**
|
||||
Constructor that parses all CH10 packets and transport headers from a byte array. Populates internal lists for transport headers, packet headers, secondary time headers, and tracks byte ranges for each packet. Sets `GoodPackets` and `RejectedPackets` counts.
|
||||
|
||||
- **`public ITransportStreamHeader[] GetTransportHeaders()`**
|
||||
Returns all parsed transport stream headers in order.
|
||||
|
||||
- **`public IPacketHeader[] GetPacketHeaders()`**
|
||||
Returns all parsed packet headers in order.
|
||||
|
||||
- **`public ISecondaryTimeFormatHeader[] GetSecondaryTimeHeaders()`**
|
||||
Returns all parsed secondary time format headers in order.
|
||||
|
||||
- **`public byte[] GetBytesForPacket(IPacketHeader packet)`**
|
||||
Returns a copy of the full packet bytes (header + payload) for a given `packet`. Returns `null` if `packet` was not parsed from this instance.
|
||||
|
||||
- **`public int GoodPackets { get; }`**
|
||||
Number of successfully parsed packets.
|
||||
|
||||
- **`public int RejectedPackets { get; }`**
|
||||
Number of packets rejected (invalid sync pattern or CRC).
|
||||
|
||||
- **`public static long GetIndexOfNextPacket(byte[] bytes, long startIndex)`**
|
||||
Scans `bytes` starting at `startIndex` for the next valid packet sync pattern (`PacketHeader.EXPECTED_SYNC_PATTERN`). Returns index of next sync, or `bytes.Length` if none found.
|
||||
|
||||
- **`public static long ReadChapter10PacketHeader(byte[] bytes, long startIndex, out IPacketHeader packetHeader)`**
|
||||
Reads a packet header from `bytes` at `startIndex`. Returns the index of the *end* of the packet (i.e., `startIndex + packetHeader.PacketLength`). Populates `packetHeader`.
|
||||
|
||||
- **`public static void WriteFilePCM(string tmats, GetNextSampleDelegate getNextSample, GetChannelLengthDelegate getChannelLength, int totalChannels, int nanoseconds, int seconds, double sampleRate, bool includeSecondaryHeader, string fileName, TickEventHandler tickEventHandler, object tickObject)`**
|
||||
Writes a PCM-format CH10 file. Writes a TMATS packet first, then interleaves time packets (Format 1 or 2 depending on `includeSecondaryHeader`) and PCM data packets. Uses `getNextSample` to read samples and `getChannelLength` to determine total samples per channel.
|
||||
|
||||
- **`public static void WriteFileAnalog(string tmats, GetNextSampleDelegate getNextSample, GetChannelLengthDelegate getChannelLength, int totalChannels, int nanoseconds, int seconds, double sampleRate, bool includeSecondaryHeader, string fileName, TickEventHandler tickEventHandler, object tickObject)`**
|
||||
Writes an analog-format CH10 file. Behavior identical to `WriteFilePCM` but produces `AnalogDataFormat1Packet` packets.
|
||||
|
||||
- **`public delegate short GetNextSampleDelegate(int channelIdx);`**
|
||||
Delegate to retrieve the next ADC sample for a given channel index.
|
||||
|
||||
- **`public delegate long GetChannelLengthDelegate(int channelIndex);`**
|
||||
Delegate to retrieve the total number of samples for a given channel.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **Packet Sync Pattern**: All valid CH10 packets must begin with `PacketHeader.EXPECTED_SYNC_PATTERN` (value not visible in source, but used in `Chapter10File` parsing and `CH10AnalogStreamDecode.ParseBytes`).
|
||||
- **CRC Validation**: Packets with `header.CheckSum != header.ComputeCheckSum()` are rejected and reported via `OnBadCRC`.
|
||||
- **Packet Length Consistency**: `ReadChapter10PacketHeader` assumes `header.PacketLength` is valid and does not exceed remaining buffer size; if it does, bytes are queued for later parsing.
|
||||
- **RTC Base**: `BASE_RTC = 141989612500056L` is used as the reference time base for computing Relative Time Counter (RTC) values in both `File.Writer` and `Chapter10File`.
|
||||
- **Sample Rate Assumption**: Export methods assume all modules in a `Test` share the same `SampleRateHz` (uses `test.Modules[0].SampleRateHz`).
|
||||
- **Transport Header**: Every CH10 packet is preceded by a 4-byte transport header (parsed by `ReadTransportHeader`).
|
||||
- **Packet Ordering**: Packet headers and transport headers are stored and returned in the order they appear in the input stream.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Dependencies *of* this module:
|
||||
- **`DTS.Common`** (e.g., `Constants`, `Utils`, `Logging`, `Enums`)
|
||||
- **`DTS.Serialization.Test`** (e.g., `Test`, `Module`, `Channel`, `AnalogInputChannel`)
|
||||
- **`IRIGCh10`** (namespace for packet types: `TMATSPacket`, `TimeDataPacket`, `PCMPacket`, `UserDefinedPacket`, `IDataPacket`, `Enums`, `PacketHeader`, etc.)
|
||||
- **`System`** (e.g., `IO`, `Net`, `Threading`, `Drawing.Text`)
|
||||
- **`DTS.DASLib.Command.SLICE.MulticastCommands`** (`MulticastCommandBase` for multicast defaults)
|
||||
|
||||
### Dependencies *on* this module:
|
||||
- **`DTS.Serialization`** (base `Serialization.File` and `Serialization.File.Writer` classes are inherited/extended)
|
||||
- **`DTS.Serialization.IRIGCH10.Packets`** (internal packet types like `TMATSPacket`, `AnalogDataFormat1Packet`, `TimePacketFormat2`, `PCMDataPacket`, `PacketHeader`, `SecondaryTimeFormatHeader`, `AbstractDataPacket`)
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **`BASE_RTC` is arbitrary**: In `File.Writer`, `BASE_RTC = 141989612500056L` is described as "we don't really have an RTC, so we make up one with an arbitrary value". This value is hardcoded and used for all exports, regardless of actual test timing.
|
||||
- **TMATS Template Files Required**: Export methods (`GetTMATSAnalog`, `GetTMATSPCM`) read template files from `@"TMTTemplates\S6ATMTTemplate_*.tmt"`. If these files are missing or misnamed, export will fail.
|
||||
- **Sample Reading Endianness**: `ReadShort` reads bytes in little-endian order (`bytes[0] + (bytes[1] << 8)`), which may differ from native file format endianness.
|
||||
- **Channel Indexing**: Channel indices in TMATS generation (`1 + channelIdx`) are 1-based, while internal indexing is 0-based.
|
||||
- **`Write` Overload Not Implemented**: The `Write(string pathname, string id, Test test, ...)` overload in `File.Writer` throws `NotImplementedException`.
|
||||
- **`Initialize` is a no-op**: The `Initialize` method has no implementation.
|
||||
- **Multicast Binding Behavior**: When `BindToAdapterIPAddress == IPAddress.Any`, `ExclusiveAddressUse = false` is set; otherwise, multicast group join uses the specific adapter.
|
||||
- **Packet Parsing Resilience**: `ParseBytes` in `CH10AnalogStreamDecode` queues incomplete packets (`QueueBytes`) if packet length exceeds available bytes, but does not flush queued bytes on subsequent calls unless new data arrives.
|
||||
- **No Support for User-Defined Packets**: `ParseBytes` logs unknown packet types but does not expose them via a delegate.
|
||||
- **RTC Calculation Assumption**: `GetRTC(currentSample, sampleRate)` assumes uniform sample timing and uses `RTC_PER_SECOND = 10000000` (10 MHz clock).
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Attributes/DescriptionDecoder.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Attributes/PacketHeaderValueAttribute.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Attributes/DataTypeVersionValueAttribute.cs
|
||||
generated_at: "2026-04-16T03:43:04.052592+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "32d5e734af040685"
|
||||
---
|
||||
|
||||
# IRIG CH10 Attribute Decoders Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides utility classes for extracting metadata annotations from .NET `enum` values, specifically tailored for IRIG CH10 data format compliance. It enables serialization logic to retrieve human-readable descriptions, maximum length constraints, packet header values, and data type version numbers associated with enum fields via custom attributes (`DescriptionAttribute`, `MaxLengthAttribute`, `PacketHeaderValueAttribute`, `DataTypeVersionValueAttribute`). These utilities bridge the gap between strongly-typed enum definitions and the string/byte-level requirements of the IRIG CH10 specification (e.g., TMATS file generation, packet header construction).
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### `DescriptionDecoder.GetDescription(Enum value)`
|
||||
- **Signature**: `public static string GetDescription(Enum value)`
|
||||
- **Behavior**: Returns the `DescriptionAttribute.Description` value attached to the enum field corresponding to `value`. If no such attribute exists, returns the enum's `ToString()` representation.
|
||||
|
||||
### `MaxLengthDecoder.GetMaxLength(Enum value)`
|
||||
- **Signature**: `public static int GetMaxLength(Enum value)`
|
||||
- **Behavior**: Returns the `Length` property of the `MaxLengthAttribute` attached to the enum field corresponding to `value`. If no such attribute exists, returns `0`.
|
||||
|
||||
### `PacketHeaderValueAttribute.GetPacketHeaderValue(Enum value)`
|
||||
- **Signature**: `public static byte GetPacketHeaderValue(Enum value)`
|
||||
- **Behavior**: Returns the `PacketHeaderValue` property of the `PacketHeaderValueAttribute` attached to the enum field corresponding to `value`. If no such attribute exists, returns `Default.PacketHeaderValue` (which is `0x00`).
|
||||
|
||||
### `DataTypeVersionValueAttribute.GetDataTypeVersionValue(Enum value)`
|
||||
- **Signature**: `public static byte GetDataTypeVersionValue(Enum value)`
|
||||
- **Behavior**: Returns the `DataTypeVersionValue` property of the `DataTypeVersionValueAttribute` attached to the enum field corresponding to `value`. If no such attribute exists, returns `Default.DataTypeVersionValue` (which is `0x00`).
|
||||
|
||||
> **Note**: The static methods `GetPacketHeaderValue` and `GetDataTypeVersionValue` are *instance methods* on their respective attribute classes, not static methods on the class itself. They are called on the attribute class (e.g., `PacketHeaderValueAttribute.GetPacketHeaderValue(someEnum)`) and operate on the enum value passed.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **Enum Field Resolution**: All decoder methods assume the `Enum` value corresponds to a valid field name in its declaring type (via `value.ToString()` → `GetField()`). If the enum value is invalid or the field name resolution fails (e.g., due to compiler-generated names or custom `ToString()` overrides), behavior is undefined (likely throws `NullReferenceException` or returns incorrect data).
|
||||
- **Attribute Uniqueness**: Methods return the *first* attribute found via `GetCustomAttributes(...)`. If multiple attributes of the same type exist on a single field, only the first is used.
|
||||
- **Default Values**: When no attribute is present:
|
||||
- `GetDescription` falls back to `value.ToString()`
|
||||
- `GetMaxLength` returns `0`
|
||||
- `GetPacketHeaderValue` returns `0x00`
|
||||
- `GetDataTypeVersionValue` returns `0x00`
|
||||
- **Attribute Scope**: `PacketHeaderValueAttribute` and `DataTypeVersionValueAttribute` are decorated with `[AttributeUsage(AttributeTargets.All)]`, meaning they *can* be applied to any program element (not just enums), though the decoders assume usage on enum fields.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Dependencies *of* this module:
|
||||
- **System.ComponentModel**: For `DescriptionAttribute`
|
||||
- **System.ComponentModel.DataAnnotations**: For `MaxLengthAttribute`
|
||||
- **System.Linq**: For `Any()` and `First()` LINQ methods
|
||||
- **System.Reflection**: For `GetType()`, `GetField()`, `GetCustomAttributes()`
|
||||
|
||||
### Dependencies *on* this module:
|
||||
- Other IRIG CH10 serialization components (not visible in source) that rely on these decoders to:
|
||||
- Generate TMATS string descriptions from enums
|
||||
- Enforce or suggest max-length constraints for string fields
|
||||
- Construct packet headers (e.g., for packet type/version identification)
|
||||
- Serialize data type version information per CH10 spec
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **No null-safety**: All methods call `value.ToString()` and `GetField(...)` without validating that `value` is non-null or that the field exists. Passing `null` or an invalid enum value will cause a `NullReferenceException`.
|
||||
- **Case sensitivity**: `value.ToString()` is used directly for `GetField()`. If the enum field name differs in casing (e.g., due to compiler optimizations or custom `ToString()` overrides), field resolution may fail.
|
||||
- **`MaxLengthAttribute` is advisory only**: As noted in the `MaxLengthDecoder` summary, CH10 specifies max lengths as *suggestions*, not hard requirements. Consumers should not assume enforcement.
|
||||
- **Default attribute behavior**: The `Default` static fields (`PacketHeaderValueAttribute.Default`, `DataTypeVersionValueAttribute.Default`) are *new instances* with `0x00` values—not singleton references to a shared default. This is safe but worth noting for equality comparisons.
|
||||
- **No validation of attribute targets**: While `PacketHeaderValueAttribute` and `DataTypeVersionValueAttribute` allow `AttributeTargets.All`, their static `Get*Value` methods assume usage on enum fields. Applying them to non-enum members (e.g., classes, methods) will likely cause runtime errors.
|
||||
- **No support for inherited attributes**: `GetCustomAttributes(..., false)` excludes inherited attributes. If attributes are defined on base enum values (in inheritance hierarchies), they will be ignored.
|
||||
|
||||
None identified from source alone beyond those above.
|
||||
@@ -0,0 +1,110 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Enums/Enums.cs
|
||||
generated_at: "2026-04-16T03:42:48.006856+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "cc430983f5236d17"
|
||||
---
|
||||
|
||||
# Documentation: `DTS.Serialization.IRIGCH10.Enums` Namespace
|
||||
|
||||
## 1. Purpose
|
||||
This module defines a set of strongly-typed enumerations used to represent standardized IRIG-106 Chapter 10 data types, time sources, time formats, and related metadata as specified in the IRIG-106 standard. These enums serve as the semantic foundation for parsing and serializing IRIG-106-compliant binary data files, mapping raw packet header values (e.g., data type codes, checksum types, time formats) to human-readable and type-safe enum members. They are used internally by serialization/deserialization logic to interpret and construct IRIG-106 packets correctly.
|
||||
|
||||
## 2. Public Interface
|
||||
All types are `public enum`s in the `DTS.Serialization.IRIGCH10.Enums` namespace. No classes, interfaces, or methods are exposed.
|
||||
|
||||
### `DataFileDataTypes`
|
||||
- **Description**: Enumerates all defined IRIG-106 Chapter 10 data format types (e.g., PCM, MIL-STD-1553, Video, Ethernet), identified by a `PacketHeaderValue` (1-byte code) and a `DataTypeVersionValue`.
|
||||
- **Key Members**:
|
||||
- `ComputerGeneratedDataFormat0` (0x00), `ComputerGeneratedDataFormat1` (0x01), ..., `ComputerGeneratedDataFormat7` (0x07)
|
||||
- `PCMDataFormat1` (0x09) — *Chapter 4 or 8*
|
||||
- `TimeDataFormat1` (0x11) — *RCC/GPS/RTC*
|
||||
- `MILSTD1553DataFormat1` (0x19) — *MIL-STD-1553B*
|
||||
- `AnalogDataFormat1` (0x21) — *Analog Data*
|
||||
- `DiscreteDataFormat1` (0x29) — *Discrete Data*
|
||||
- `MessageDataFormat0` (0x30) — *Generic Message Data*
|
||||
- `ARINC429DataFormat0` (0x38) — *ARINC-429 Data*
|
||||
- `VideoDataFormat0` (0x40) — *MPEG-2/H.264 Video*
|
||||
- `VideoDataFormat1` (0x41) — *ISO 13818-1 MPEG-2*
|
||||
- `VideoDataFormat2` (0x42) — *ISO 14496 MPEG-4 Part10 110 AVC/H.264*
|
||||
- `VideoDataFormat3` (0x43) — *MJPEG* (version 0x07)
|
||||
- `VideoDataFormat4` (0x44) — *MJPEG 2000* (version 0x07)
|
||||
- `ImageDataFormat0` (0x48) — *Image Data*
|
||||
- `ImageDataFormat1` (0x49) — *Still Imagery*
|
||||
- `ImageDataFormat2` (0x4A) — *Dynamic Imagery*
|
||||
- `UARTDataFormat0` (0x50) — *UART Data*
|
||||
- `IEEE1394DataFormat0` (0x58) — *IEEE 1394 Transaction*
|
||||
- `IEEE1394DataFormat1` (0x59) — *IEEE 1394 Physical Layer*
|
||||
- `ParallelDataFormat0` (0x60) — *Parallel Data*
|
||||
- `EthernetDataFormat0` (0x68) — *Ethernet Data* (version 0x07)
|
||||
- `EthernetDataFormat1` (0x69) — *Ethernet UDP Payload*
|
||||
- `TSPI_CTSDataFormat0` (0x70) — *GPS NMEA-RTCM*
|
||||
- `TSPI_CTSDataFormat1` (0x71) — *EAG ACMI*
|
||||
- `TSPI_CTSDataFormat2` (0x72) — *ACTTS*
|
||||
- `ControllerAreaNetworkBus` (0x78) — *CAN Bus*
|
||||
- `FibreChannelDataFormat0` (0x79) — *Fibre Channel Data* (version 0x07)
|
||||
- **Note**: All formats follow a pattern: `XxxDataFormatN`, where `N` (0–7) allows for vendor-specific or variant definitions. Only `Format1` variants (e.g., `AnalogDataFormat1`) are standardized; others are reserved.
|
||||
|
||||
### `TimeSource`
|
||||
- **Description**: Specifies the origin of time metadata in a packet.
|
||||
- **Members**:
|
||||
- `Internal` (0x00) — *Time derived from a clock in the recorder*
|
||||
- `External` (0x01) — *Time derived from a clock not in the recorder*
|
||||
- `InternalFromRMM` (0x02) — *Internal from RMM (Time derived from the clock in the RMM)*
|
||||
- `None` (0x0F) — *No time source*
|
||||
|
||||
### `TimeFormats`
|
||||
- **Description**: Specifies the encoding format of time data (e.g., IRIG-B, UTC, GPS).
|
||||
- **Members**:
|
||||
- `IRIGB` (0x00) — *IRIG-B*
|
||||
- `IRIGA` (0x01) — *IRIG-A*
|
||||
- `IRIGG` (0x02) — *IRIG-G*
|
||||
- `RTC` (0x03) — *Real-Time Clock*
|
||||
- `UTC` (0x04) — *UTC Time from GPS*
|
||||
- `GPS` (0x05) — *Native GPS Time*
|
||||
- `None` (0x0F) — *No time format*
|
||||
|
||||
### `DataTypeVersion`
|
||||
- **Description**: Represents the version of the IRIG-106 standard used for the data type definition.
|
||||
- **Members**:
|
||||
- `InitialRelease` (0x01) — *Initial Release (IRIG-106-04)*
|
||||
- `TG78` (0x02) — *TG-78 (IRIG-106-05)*
|
||||
- `IRIG106_07` (0x03) — *IRIG-106-07*
|
||||
|
||||
### `SecondaryHeaderTimeFormat`
|
||||
- **Description**: Indicates the binary format of time in the secondary header (if present).
|
||||
- **Members**:
|
||||
- `IRIG106Chapter4` (0x00) — *IRIG 106 Chapter 4 binary weighted 48-bit time format*
|
||||
- `IEEE1588` (0x01) — *IEEE-1588 Time format*
|
||||
|
||||
### `DataCheckSumType`
|
||||
- **Description**: Specifies the checksum algorithm used for packet integrity.
|
||||
- **Members**:
|
||||
- `None` (0x00)
|
||||
- `EightBit` (0x01)
|
||||
- `SixteenBit` (0x02)
|
||||
- `ThirtyTwoBit` (0x03)
|
||||
|
||||
## 3. Invariants
|
||||
- **`PacketHeaderValue` is unique per enum member**: Each enum value is annotated with `[PacketHeaderValue(byte)]`, and no two members share the same value. This ensures unambiguous mapping between raw bytes and enum members.
|
||||
- **`DataTypeVersionValue` is consistent per `DataFileDataTypes` member**: Every `DataFileDataTypes` member has exactly one `[DataTypeVersionValue(byte)]` attribute. Values observed are `0x06` (most common) and `0x07` (e.g., `ComputerGeneratedDataFormat1`, `VideoDataFormat3`, `VideoDataFormat4`, `EthernetDataFormat0`, `FibreChannelDataFormat0`).
|
||||
- **Reserved formats are strictly reserved**: All enum members with descriptions containing “Reserved for future use” must not be interpreted as active data types. Their `PacketHeaderValue`s are contiguous in blocks (e.g., `0x04`–`0x07`, `0x0A`–`0x0F`, etc.), but their usage is undefined.
|
||||
- **No overlapping `PacketHeaderValue`s across enums**: While not enforced in code, the values are allocated per IRIG-106 spec to avoid ambiguity (e.g., `TimeSource.None = 0x0F` does not conflict with `TimeFormats.None = 0x0F` because they apply to different contexts).
|
||||
|
||||
## 4. Dependencies
|
||||
- **Internal dependencies**:
|
||||
- `DTS.Serialization.IRIGCh10.Attributes` — Custom attributes `[PacketHeaderValue]`, `[DataTypeVersionValue]`, and `[Description]` are defined here (not shown, but referenced).
|
||||
- **External dependencies**:
|
||||
- `System.ComponentModel` — Used for `[Description]` attribute.
|
||||
- **Consumers** (inferred from naming and structure):
|
||||
- Serialization/deserialization logic for IRIG-106 Chapter 10 files (e.g., packet header parsers, metadata extractors).
|
||||
- Likely used in `Packet` or `Stream` classes in sibling namespaces (e.g., `DTS.Serialization.IRIGCH10.Packets`).
|
||||
|
||||
## 5. Gotchas
|
||||
- **Typo in enum member name**: `FibreChannelDataFormats1`, `FibreChannelDataFormats2`, etc. (note the trailing `s` in `Formats`) — inconsistent with naming pattern (`FibreChannelDataFormat0`). Likely a typo; verify usage in deserialization logic.
|
||||
- **Version inconsistency**: Most `DataFileDataTypes` use `DataTypeVersionValue(0x06)`, but `ComputerGeneratedDataFormat1`, `VideoDataFormat3`, `VideoDataFormat4`, `EthernetDataFormat0`, and all `FibreChannelDataFormats*` use `0x07`. Ensure deserialization logic handles version-specific parsing.
|
||||
- **`None` values are context-sensitive**: `TimeSource.None` (0x0F) and `TimeFormats.None` (0x0F) are distinct and valid in their respective contexts (e.g., absence of time metadata), but must not be confused.
|
||||
- **No validation of reserved ranges**: The enum does not prevent invalid or future-use values (e.g., `0x80`–`0xFF` are undefined). Consumers must handle unknown values gracefully.
|
||||
- **Missing `Description` attributes**: Some members (e.g., `MILSTD1553DataFormat0`, `AnalogDataFormat0`) lack `[Description]`, relying solely on naming. This may cause issues if `Description` is used for logging or UI.
|
||||
@@ -0,0 +1,221 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Packets/ITransportStreamHeader.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Packets/ISecondaryTimeFormatHeader.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Packets/TransportStreamHeader.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Packets/SecondaryTimeFormatHeader.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Packets/TimeDataPacket.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Packets/TMATSPacket.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Packets/RootRecorderIndexPacket.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Packets/RecorderIndexPacket.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Packets/TimePacketFormat2.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Packets/IDataPacket.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Packets/TimePacketFormat1.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Packets/AnalogDataFormat1Packet.cs
|
||||
generated_at: "2026-04-16T03:43:44.837011+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "a37b40770bf1428d"
|
||||
---
|
||||
|
||||
# IRIG CH10 Packet Serialization Module Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides serialization and deserialization support for IRIG CH10 data packets, implementing core packet types required for recording and playback of time-synchronized embedded system data streams. It defines interfaces and concrete classes for transport headers, secondary time headers, and various data packet formats—including time data (Formats 1 and 2), analog data (Format 1), TMATS metadata, and recorder indexing structures—enabling interoperability with IRIG CH10-compliant systems. The module is designed for use in data acquisition and post-processing pipelines where precise time-stamping and structured binary packet formatting are required.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### Interfaces
|
||||
|
||||
- **`ITransportStreamHeader`**
|
||||
- `int MessageFormat { get; }` — 4-bit field identifying the message format (must be `1` per spec).
|
||||
- `int MessageType { get; }` — 4-bit field identifying the message type (must be `0` per spec).
|
||||
- `int SequenceNumber { get; }` — 24-bit UDP sequence number, incremented per packet.
|
||||
|
||||
- **`ISecondaryTimeFormatHeader`**
|
||||
- `int NanoSeconds { get; }` — Nanosecond component of the time stamp.
|
||||
- `int Seconds { get; }` — Seconds since Unix epoch (1970-01-01).
|
||||
- `ushort Reserved { get; }` — Reserved field (always `0` in current implementation).
|
||||
- `ushort CheckSum { get; }` — 8-bit checksum over preceding fields (stored as `ushort`).
|
||||
- `DateTime LocalTime { get; }` — Computed local time from `Seconds` and `NanoSeconds`.
|
||||
|
||||
- **`IDataPacket`**
|
||||
- `IPacketHeader PacketHeader { get; }` — Access to the packet header metadata.
|
||||
- `uint ComputeCheckSum()` — Computes CRC32 checksum over data bytes.
|
||||
- `byte[] GetBytes()` — Serializes the entire packet to a byte array.
|
||||
- `void SetRTC(long rtc)` — Sets the Real-Time Counter (10 MHz) value.
|
||||
- `void SetDataVersion(DataTypeVersion version)` — Sets the data version field in the header.
|
||||
- `void SetChannelID(ushort channelID)` — Sets the channel ID.
|
||||
- `void SetSequenceNumber(ushort seq)` — Sets the packet sequence number.
|
||||
|
||||
### Concrete Classes
|
||||
|
||||
- **`TransportStreamHeader`** (implements `ITransportStreamHeader`)
|
||||
- `TransportStreamHeader()` — Default constructor (fields uninitialized).
|
||||
- `TransportStreamHeader(byte[] input)` — Parses 4-byte header; validates length (`TRANSPORT_HEADER_LENGTH = 4`), extracts `MessageFormat`, `MessageType`, and `SequenceNumber` via bit manipulation.
|
||||
- `const int TRANSPORT_HEADER_LENGTH = 4` — Header size in bytes.
|
||||
|
||||
- **`SecondaryTimeFormatHeader`** (implements `ISecondaryTimeFormatHeader`)
|
||||
- `SecondaryTimeFormatHeader(byte[] input)` — Parses 12-byte header; validates checksum via `Utils.Utils.GetCheckSum8`; logs mismatch via `Trace.WriteLine`.
|
||||
- `static byte[] GetBytes(int nanoseconds, int seconds)` — Serializes header with `Reserved=0`, computes checksum.
|
||||
- `const int SECONDARY_TIME_HEADER_LENGTH = 12` — Header size in bytes.
|
||||
|
||||
- **`TimeDataPacket`** (implements `IDataPacket`, extends `AbstractDataPacket`)
|
||||
- `TimeDataPacket()` — Initializes with `DataFileDataTypes.TimeDataFormat1`, 12-byte `_dataBytes`.
|
||||
- `DateTime GetDateTime()` — Returns internal `_dt`.
|
||||
- `void SetTime(DateTime dt)` — Encodes time fields (ms/10, sec, min, hour, day, month, year) as BCD into `_dataBytes[4..11]`.
|
||||
- `void SetTimeSource(byte b)` — Sets time source bits (0–3) in `_dataBytes[0]`.
|
||||
- `void SetTimeSource(TimeSource src)` — Sets time source using `PacketHeaderValueAttribute.GetPacketHeaderValue(src)`; bit-reverses order (per CH10 spec).
|
||||
- `void SetTimeFormat(TimeFormats fmt)` — Sets time format bits (4–7) similarly.
|
||||
|
||||
- **`TMATSPacket`** (implements `IDataPacket`, extends `AbstractDataPacket`)
|
||||
- `TMATSPacket(int nanoseconds, int seconds, string tmatsDoc, bool secondaryHeaderPresent)` — Constructs TMATS packet with ASCII/XML doc; sets data version (`0x01` or `0x09`).
|
||||
- `TMATSPacket(byte[] bytes)` — Deserializes from byte array.
|
||||
- `bool XMLFormat { get; }` — Extracted from bit 9 of `ChannelSpecificDataWord`.
|
||||
- `bool SetupRecordConfigurationChange { get; }` — Extracted from bit 8.
|
||||
- `RCCChapter10Versions Chapter10Version { get; }` — Extracted from bits 0–7; maps to enum (`RESERVED`, `RCC_106_07`, ..., `RCC_106_15`).
|
||||
- `string TMATSDocument { get; }` — Extracts TMATS string from `_dataBytes` after skipping CSDW and optional secondary header.
|
||||
|
||||
- **`RootRecorderIndexPacket`** (implements `IDataPacket`, extends `AbstractDataPacket`)
|
||||
- `RootRecorderIndexPacket(DateTime dt)` — Initializes with `DataFileDataTypes.ComputerGeneratedDataFormat3`.
|
||||
- `void SetRootPacketAddress(long address)` — Stores 8-byte address.
|
||||
- `void AddRecordingIndex(RecordingIndexIndex index)` — Adds to `_indices` list.
|
||||
- `override byte[] GetBytes()` — Appends a self-referencing index entry before serializing.
|
||||
|
||||
- **`RecordingIndexIndex`**
|
||||
- `const int SIZE = 24` — 8 bytes (RTC) + 8 bytes (DateTime BCD) + 8 bytes (data packet offset).
|
||||
- `RecordingIndexIndex(long rtc, long offset, DateTime dt)` — Constructor.
|
||||
- `byte[] GetBytes()` — Serializes fields in order: RTC, DateTime (BCD), offset.
|
||||
|
||||
- **`RecorderIndexPacket`** (implements `IDataPacket`, extends `AbstractDataPacket`)
|
||||
- `RecorderIndexPacket()` — Initializes with `DataFileDataTypes.ComputerGeneratedDataFormat3`.
|
||||
- `DateTime GetDateTime()` — Returns `GetDateTime()` of first `RecordingIndex`.
|
||||
- `int NumberOfEntries { get; }` — Count of `_indices`.
|
||||
- `void AddRecordingIndex(RecordingIndex index)` — Adds to `_indices`.
|
||||
- `override byte[] GetBytes()` — Serializes channel-specific data word, root address, and indices.
|
||||
|
||||
- **`RecordingIndex`**
|
||||
- `const int SIZE = 35` — 8 (RTC) + 8 (DateTime BCD) + 2 (ChannelId) + 1 (DataType) + 1 (Reserved) + 8 (offset).
|
||||
- `DateTime GetDateTime()` — Returns stored `_dt`.
|
||||
- `RecordingIndex(long rtc, long offset, DateTime dt)` — Constructor.
|
||||
- `byte[] GetBytes()` — Serializes fields.
|
||||
|
||||
- **`TimePacketFormat2`** (implements `IDataPacket`, extends `AbstractDataPacket`)
|
||||
- `TimePacketFormat2(byte sequenceNumber, bool rtcSyncError, int nanoseconds, int seconds, long rtc, bool includeSecondaryHeader)` — Constructor.
|
||||
- `TimePacketFormat2(byte[] bytes)` — Deserializes from byte array.
|
||||
- `DateTime LocalTimeOfFirstSample { get; }` — Populated if secondary header present.
|
||||
- `enum NetworkTimeFormats` — Values: `NetworkTimeProtocolVersion3`, `IEEE1588_2002`, `IEEE1588_2008`, `RESERVED`.
|
||||
- `NetworkTimeFormats NetworkTimeFormat { get; set; }` — Bits 7–4 of CSDW.
|
||||
- `enum TimeStatuses` — Values: `TimeNotValid`, `TimeValid`, `RESERVED`.
|
||||
- `TimeStatuses TimeStatus { get; set; }` — Bits 3–0 of CSDW.
|
||||
- `uint UnsignedSeconds { get; }` — Parsed from data section.
|
||||
- `uint UnsignedNanoSeconds { get; }` — Parsed from data section.
|
||||
- `string PTPTime { get; }` — Formatted via `PTP1588Timestamps.ToDateTimeString(...)`.
|
||||
|
||||
- **`TimePacketFormat1`** (implements `IDataPacket`, extends `AbstractDataPacket`)
|
||||
- `TimePacketFormat1(byte sequenceNumber, DateTime packetTime, long rtc, int nanoseconds, int seconds)` — Constructor.
|
||||
- `enum IRIGTimeSource` — Values: `IRIG_TCG_freewheeling`, ..., `RESERVED`.
|
||||
- `IRIGTimeSource ITS { get; set; }` — Bits 15–12 of CSDW (not serialized per comment).
|
||||
- `enum TimeFormats` — Values: `IRIG_B`, `IRIG_A`, `IRIG_G`, `RTC`, `UTC`, `NativeGPS`, `RESERVED`, `NONE`.
|
||||
- `TimeFormats TimeFormat { get; set; }` — Bits 7–4 of CSDW.
|
||||
- `enum TimeSources` — Values: `Internal`, `External`, `InternalFromRMM`, `Reserved`, `None`.
|
||||
- `TimeSources TimeSource { get; set; }` — Bits 3–0 of CSDW.
|
||||
- `enum DateFormats` — Values: `IRIGDayAvailable`, `MonthAndYearAvailable`.
|
||||
- `DateFormats DateFormat { get; set; }` — Bit 9 of CSDW.
|
||||
- `DateTime TimePacketTime { get; set; }` — Stored time.
|
||||
- `bool IsLeapYear { get; set; }` — Bit 8 of CSDW.
|
||||
|
||||
- **`AnalogDataFormat1Packet`** (implements `IDataPacket`, extends `AbstractDataPacket`)
|
||||
- `AnalogDataFormat1Packet(int nanoseconds, int seconds, Chapter10File.GetNextSampleDelegate getNextSample, int totalChannels, long channelLength, long rtc, long numSamples, long currentSample, byte sequenceNumber, ushort channelId, bool includeSecondaryHeader)` — Constructor.
|
||||
- `AnalogDataFormat1Packet(byte[] bytes)` — Deserializes from byte array.
|
||||
- `DateTime LocalTimeOfFirstSample { get; }` — Populated if secondary header present.
|
||||
- `bool Same { get; set; }` — Bit 28 of CSDW.
|
||||
- `int Factor { get; set; }` — Bits 27–24 of CSDW.
|
||||
- `int TotChan { get; set; }` — Bits 23–16 of CSDW.
|
||||
- `long Subchan { get; set; }` — Bits 15–8 of CSDW.
|
||||
- `long Length { get; set; }` — Bits 7–2 of CSDW.
|
||||
- `enum Modes` — Values: `DataIsPacked`, `DataIsUnpackedLSBPadded`, `Reserved`, `DataIsUnpackedMSBPadded`.
|
||||
- `Modes Mode { get; set; }` — Bits 1–0 of CSDW.
|
||||
- `SampleData[] Samples { get; }` — Array of sample records; each contains `short[] ChannelData`.
|
||||
|
||||
- **`AbstractDataPacket`** (abstract base class)
|
||||
- `protected uint ChannelSpecificDataWord { get; protected set; }` — CSDW field.
|
||||
- `IPacketHeader PacketHeader { get; protected set; }` — Header reference.
|
||||
- `void SetCSDWBit(int bit, bool value)` — Sets/clears a single bit in CSDW.
|
||||
- `bool GetCSDWBit(int bit)` — Reads a bit from CSDW.
|
||||
- `protected int CommonHeaderWork(...)` — Initializes header fields, computes packet length, handles padding, and writes secondary header/CSDW into `_dataBytes`.
|
||||
- `uint ComputeCheckSum()` — Returns CRC32 via `Utils.Utils.GetCheckSum32`.
|
||||
- `void SetRTC(long rtc)` / `long GetRTC()` — Manages `_rtc` and header RTC.
|
||||
- `const long BASE_RTC = 141989612500056L` — Reference RTC value.
|
||||
- `virtual byte[] GetBytes()` — Serializes header + `_dataBytes`.
|
||||
- Protected constructors for initialization and deserialization.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **TransportStreamHeader**:
|
||||
- `MessageFormat` must be `1`.
|
||||
- `MessageType` must be `0`.
|
||||
- `SequenceNumber` is a 24-bit integer (range `0x000000`–`0xFFFFFF`).
|
||||
- Input byte array must be exactly 4 bytes.
|
||||
|
||||
- **SecondaryTimeFormatHeader**:
|
||||
- Input byte array must be exactly 12 bytes.
|
||||
- `CheckSum` is validated against `Utils.Utils.GetCheckSum8`; mismatch triggers a trace warning but does not throw.
|
||||
- `LocalTime` is computed as `new DateTime(1970, 1, 1).AddSeconds(Seconds).AddTicks(NanoSeconds / 100).ToLocalTime()`.
|
||||
|
||||
- **Data Packets**:
|
||||
- All packets must have a valid `IPacketHeader` with correct `DataFileDataTypes`.
|
||||
- `PacketHeader.PacketLength` is padded to a multiple of 4 bytes.
|
||||
- `ChannelSpecificDataWord` is always 4 bytes and written into `_dataBytes` after optional secondary header.
|
||||
- `ComputeCheckSum()` operates over `_dataBytes` only (not header).
|
||||
- `SetSequenceNumber(ushort seq)` writes only the least significant byte of `seq` to `PacketHeader.SequenceNum`.
|
||||
|
||||
- **TimeDataPacket**:
|
||||
- `_dataBytes` is fixed at 12 bytes.
|
||||
- Time fields are encoded in BCD format.
|
||||
|
||||
- **TMATSPacket**:
|
||||
- `TMATSDocument` extraction assumes ASCII encoding and skips 4-byte CSDW and optional secondary header.
|
||||
|
||||
- **AnalogDataFormat1Packet**:
|
||||
- Data is stored as big-endian `ushort` (MSB first), converted to signed `short` with offset `+0x8000`.
|
||||
- `Mode` defaults to `DataIsUnpackedMSBPadded`; `Length` defaults to `16`.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Internal Dependencies
|
||||
- **`DTS.Serialization.IRIGCH10.Enums`** — Defines `DataFileDataTypes`, `DataTypeVersion`, `TimeSource`, `TimeFormats`, etc.
|
||||
- **`DTS.Serialization.IRIGCH10.Attributes`** — Used by `TimeDataPacket` for `PacketHeaderValueAttribute.GetPacketHeaderValue`.
|
||||
- **`DTS.Serialization.IRIGCH10.Packets`** — Contains `PacketHeader`, `IPacketHeader`, `ITransportStreamHeader`, `ISecondaryTimeFormatHeader`, and related classes.
|
||||
- **`DTS.Common.Utilities`** — Provides `Utils` class with methods:
|
||||
- `BitArrayToInt32(BitArray, int, int)`
|
||||
- `SetBits(BitArray, uint, int, int)`
|
||||
- `GetCheckSum8(byte[])`
|
||||
- `GetCheckSum32(byte[])`
|
||||
- `GetBCDBytes(int)`
|
||||
|
||||
### External Dependencies
|
||||
- **`System`** — Core types (`BitConverter`, `BitArray`, `DateTime`, `Encoding`, `Array`, `Buffer`, `MemoryStream`, `BinaryWriter`).
|
||||
- **`System.IO`** — For `MemoryStream`, `BinaryWriter`.
|
||||
|
||||
### Inferred Usage
|
||||
- `AbstractDataPacket` and `IDataPacket` are used by higher-level file writers/readers (e.g., `Chapter10File`).
|
||||
- `TransportStreamHeader` is likely used in UDP packet serialization/deserialization.
|
||||
- `SecondaryTimeFormatHeader` is used in `TimePacketFormat2`, `AnalogDataFormat1Packet`, and `TMATSPacket` when `secondaryHeaderPresent=true`.
|
||||
- `PTP1588Timestamps.ToDateTimeString(...)` is referenced but not defined in source—assumed external.
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **`TimeDataPacket.SetSequenceNumber`** writes only the LSB of the input `ushort`, ignoring the high byte.
|
||||
- **`TransportStreamHeader`** performs bit extraction in reverse order (LSB-first) via `BitArrayToInt32(bits, start, end)`, where `end` is inclusive and higher than `start`.
|
||||
- **`SecondaryTimeFormatHeader.CheckSum`** is stored as `ushort` but computed as 8-bit; only the low byte is meaningful.
|
||||
- **`TimePacketFormat1.ITS`** is documented as *not serialized* to CSDW due to validation tool incompatibility (commented as of 2023-10-27).
|
||||
- **`AnalogDataFormat1Packet`** uses two different data versions: `0x06` (DASSAULT) for secondary headers, `0x01` (CH10 v105) otherwise.
|
||||
- **`RecordingIndexIndex` and `RecordingIndex`** store `DateTime` in BCD format (e.g., `0x12` for month=12), not binary.
|
||||
- **`TimeDataPacket.SetTime`** encodes `dt.Millisecond / 10` (tens of milliseconds), not full milliseconds.
|
||||
- **`AbstractDataPacket.SetRTC`** updates both `_rtc` and `PacketHeader.SetRTC(rtc)`; `GetRTC()` returns `_rtc`.
|
||||
- **`TMATSPacket.TMATSDocument`** extraction assumes ASCII encoding; no validation of XML/ASCII format beyond `XMLFormat` bit.
|
||||
- **`TransportStreamHeader`** constructor throws `NullReferenceException` for null input (should be `ArgumentNullException` per .NET conventions).
|
||||
- **`TimePacketFormat2.TimeStatus`** and **`NetworkTimeFormat`** enums include `RESERVED` as a valid return value, but deserialization does not throw on unknown values—defaults to `RESERVED`.
|
||||
- **`AnalogDataFormat1Packet`** samples are stored as `short[]` in `SampleData`, but the underlying data is big-endian `ushort`; conversion is handled in `GetChannels`.
|
||||
@@ -0,0 +1,181 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/TMATS/DescriptionDecoder.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/TMATS/TMATSectionNumbered.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/TMATS/TMATSSection.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/TMATS/TMATS.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/TMATS/GeneralInformation.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/TMATS/PCM.cs
|
||||
generated_at: "2026-04-16T03:43:40.628941+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "3279c734bbc2d68c"
|
||||
---
|
||||
|
||||
# Documentation: TMATS Serialization Module
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides serialization infrastructure for generating TMATS (Telemetry and Tracking Data Format Standard) documents compliant with IRIG 106 Chapter 10. It enables structured construction of TMATS records by encapsulating attribute-value pairs, handling numbered sections (e.g., per-channel PCM data), and enforcing formatting rules derived from metadata attributes (`DescriptionAttribute`, `MaxLengthAttribute`). The module serves as the foundational serialization layer for converting in-memory telemetry configuration objects into the standardized text-based TMATS format used in IRIG 106-compliant telemetry files.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### `DescriptionDecoder.GetDescription(Enum value)`
|
||||
- **Signature**: `public static string GetDescription(Enum value)`
|
||||
- **Behavior**: Retrieves the `DescriptionAttribute.Description` value associated with the given enum field. If no attribute exists, returns the enum's `ToString()` value.
|
||||
|
||||
### `MaxLengthDecoder.GetMaxLength(Enum value)`
|
||||
- **Signature**: `public static int GetMaxLength(Enum value)`
|
||||
- **Behavior**: Retrieves the `Length` property of the `MaxLengthAttribute` associated with the given enum field. If no attribute exists, returns `0`.
|
||||
|
||||
### `TMATSSection<T>.SetValue(T tag, string value)`
|
||||
- **Signature**: `public void SetValue(T tag, string value) where T : Enum`
|
||||
- **Behavior**: Stores the value for the specified enum tag in an internal dictionary.
|
||||
|
||||
### `TMATSSection<T>.GetValue(T tag)`
|
||||
- **Signature**: `public string GetValue(T tag) where T : Enum`
|
||||
- **Behavior**: Returns the stored value for the given tag, or `null` if not set.
|
||||
|
||||
### `TMATSSection<T>.SetDate(T tag, DateTime? value)`
|
||||
- **Signature**: `public void SetDate(T tag, DateTime? value)`
|
||||
- **Behavior**: Stores a date as `"MM-DD-YYYY"` string (e.g., `"11-20-2018"`), or an empty string if `value` is `null`.
|
||||
|
||||
### `TMATSSection<T>.GetDate(T tag)`
|
||||
- **Signature**: `public DateTime? GetDate(T tag)`
|
||||
- **Behavior**: Parses and returns a `DateTime?` from the stored value using `"MM-DD-YYYY"` format. Returns `null` if not set or invalid.
|
||||
|
||||
### `TMATSSection<T>.GetIntOrNull(T tag)`
|
||||
- **Signature**: `public int? GetIntOrNull(T tag)`
|
||||
- **Behavior**: Parses and returns an `int?` from the stored value. Returns `null` if not set or invalid.
|
||||
|
||||
### `TMATSSection<T>.SetIntOrNull(T tag, int? val)`
|
||||
- **Signature**: `public void SetIntOrNull(T tag, int? val)`
|
||||
- **Behavior**: Stores the integer as a string, or an empty string if `val` is `null`.
|
||||
|
||||
### `TMATSSection<T>.SetValueWithLength(T tag, string value)`
|
||||
- **Signature**: `public void SetValueWithLength(T tag, string value)`
|
||||
- **Behavior**: Stores the value. *Note: Length validation is currently disabled (commented out in source).*
|
||||
|
||||
### `TMATSSection<T>.Serialize()`
|
||||
- **Signature**: `public virtual string Serialize()`
|
||||
- **Behavior**: Serializes all non-empty tag-value pairs into lines of the format `Identifier\Attribute:value;` or `Identifier-N\Attribute:value;` if `_number >= 0`.
|
||||
|
||||
### `TMATSSection<T>.Serialize(T tag)`
|
||||
- **Signature**: `protected string Serialize(T tag)`
|
||||
- **Behavior**: Serializes a single tag-value pair. Returns `null` if value is empty/whitespace.
|
||||
|
||||
### `TMATSSection<T>` constructors
|
||||
- **`TMATSSection()`**: Default constructor for unnumbered sections.
|
||||
- **`TMATSSection(AttributeIdentifiers attribute, int number)`**: Constructor for numbered sections (e.g., per-channel PCM). Sets `_attribute` and `_number`.
|
||||
|
||||
### `TMATSectionNumbered<T>.SetValue(T tag, string value)`
|
||||
- **Signature**: `public void SetValue(T tag, string value) where T : Enum`
|
||||
- **Behavior**: Stores value for the given tag in internal dictionary.
|
||||
|
||||
### `TMATSectionNumbered<T>.GetValue(T tag)`
|
||||
- **Signature**: `public string GetValue(T tag) where T : Enum`
|
||||
- **Behavior**: Returns stored value for the tag, or `null`.
|
||||
|
||||
### `TMATSectionNumbered<T>.Serialize(int number)`
|
||||
- **Signature**: `public string Serialize(int number)`
|
||||
- **Behavior**: Serializes all non-empty tag-value pairs. Format:
|
||||
`Identifier-N\Attribute<number>:value;` if `Number > 0`, else `Identifier\Attribute<number>:value;`.
|
||||
|
||||
### `TMATSectionNumbered<T>.SetValueWithLength(T tag, string value)`
|
||||
- **Signature**: `public void SetValueWithLength(T tag, string value)`
|
||||
- **Behavior**: Calls `SetValue(tag, value)`. *Note: Length validation is currently disabled.*
|
||||
|
||||
### `TMATSectionNumberedArray<T>.SetValue(int number, T tag, string value)`
|
||||
- **Signature**: `public virtual void SetValue(int number, T tag, string value)`
|
||||
- **Behavior**: Ensures `_items` has `number` elements via `SetCount`, then calls `SetValueWithLength` on the `number`-th item (1-based index).
|
||||
|
||||
### `TMATSectionNumberedArray<T>.GetValue(int number, T tag)`
|
||||
- **Signature**: `public string GetValue(int number, T tag)`
|
||||
- **Behavior**: Returns value from the `number`-th item (1-based), or `null`.
|
||||
|
||||
### `TMATSectionNumberedArray<T>.Serialize()`
|
||||
- **Signature**: `public string Serialize()`
|
||||
- **Behavior**: Serializes all items. Includes a header line `Identifier-N\Tag:Count;` if `_numberedTag` is non-empty. Then serializes each item with its 1-based index.
|
||||
|
||||
### `TMATSectionNumberedArray<T>.SetCount(int count)`
|
||||
- **Signature**: `public void SetCount(int count)`
|
||||
- **Behavior**: Resizes `_items` list to `count`. Throws `Exception` if `count > _maxNumber`. If shrinking, truncates items; if expanding, creates new `TMATSectionNumbered<T>` instances with `_attributeIdentifier` and `_number` set.
|
||||
|
||||
### `TMATSectionNumberedArray<T>.GetCount()`
|
||||
- **Signature**: `public int GetCount() => _items.Count`
|
||||
|
||||
### `AttributeIdentifiers` enum
|
||||
- **Members**: `GeneralInformation`, `TransmitionAttributes`, `StorageSourceAttributes`, `MultiplexingAttributes`, `PCMFormatAttributes`, `PCMMeasurementDescription`, `BusDataAttributes`, `PacketFormatAttributes`, `PAMAttributes`, `DataConversionAttributes`, `AirborneHardwareAttributes`, `VendorSpecificAttributes`
|
||||
- **Behavior**: Each member has a `[Description]` attribute (e.g., `"G"`, `"P"`) used in serialization.
|
||||
|
||||
### `GeneralInformationGroup` class
|
||||
- **Key Properties**:
|
||||
- `ProgramName`, `TestItem`, `IRIG106RevisionLevel`, `OriginationDate`, etc.
|
||||
- `NumberOfDataSources`, `NumberOfPointsOfContact`
|
||||
- `PreTestRequirement`, `PostTestRequirement`
|
||||
- **Methods**:
|
||||
- `SetDataSourceField(int number, DataSourceIdentificationTags tag, string value)`
|
||||
Enforces uniqueness of `DataSourceID` (throws `Exception` if duplicate).
|
||||
- `SetDataSourceType(int number, DataSourceTypes sourceType)`
|
||||
- `SetContactField(int number, PointOfContactTags tag, string value)`
|
||||
- **Nested Types**:
|
||||
- `CommentSection`, `SecuritySection`, `Information` (with nested `PointOfContactTags`, `DataSourceIdentificationTags`, `DataSourceTypes`, `TestInformationTags`).
|
||||
- `Information.DataSourceIdentificationTags.DataSourceID` has `[MaxLength(32)]`.
|
||||
|
||||
### `PCM` class
|
||||
- **Key Properties**:
|
||||
- `DataLinkName`, `PCMCode`, `BitsPerSecond`, `DataRandomized`, `Polarity`, `DataDirection`, `TypeFormat`, `NumberOfBitsInCommonWordLength`, `WordTransferOrder`, `PCMWordParity`
|
||||
- **Constructors**:
|
||||
- `PCM(int number)` → calls `base(AttributeIdentifiers.PCMFormatAttributes, number)`
|
||||
- **Nested Types**:
|
||||
- `PCMTypeFormat` (section for type-specific attributes like `TypeFormat`, `CommonWordLength`, etc.)
|
||||
- `MinorFrameSection` (section for minor frame sync data)
|
||||
- `PCMTypeFormats`, `PCMWordTransferOrders`, `PCMWordParities`, `PCMCodes`, `Polarities`, `PCMDataDirections` enums.
|
||||
|
||||
### `MinorFrameSection` class
|
||||
- **Key Properties**:
|
||||
- `NumberOfMinorFramesInAMajorFrame`, `NumberOfWordsInMinorFrame`, `NumberOfBitsInMinorFrame`, `SyncLength`, `SynchronizationPattern`
|
||||
- **Constructor**: `MinorFrameSection(int number=1)` → `base(AttributeIdentifiers.PCMFormatAttributes, number)`
|
||||
|
||||
### `TMATSCreationTest.CreateTMATS()`
|
||||
- **Signature**: `public static string CreateTMATS()`
|
||||
- **Behavior**: Demonstrates usage by constructing a sample TMATS document for a PCM telemetry system with 4 channels (1 time, 2 PCM, 1 message data). Returns the serialized string.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **Tag Uniqueness per Section**: In `GeneralInformationGroup.Information`, `DataSourceID` values must be unique across all data sources (enforced in `SetDataSourceField`).
|
||||
- **Numbered Sections**: Sections requiring numbering (e.g., PCM, MinorFrame) use `_number` to generate identifiers like `P-1\DLN:value;`.
|
||||
- **Date Format**: Dates are stored and parsed strictly as `"MM-DD-YYYY"` (e.g., `"11-20-2018"`).
|
||||
- **Enum Serialization**: Enum values are serialized using their `[Description]` attribute, falling back to `ToString()` if missing.
|
||||
- **Empty Value Handling**: Empty/whitespace values are skipped during serialization (`string.IsNullOrWhiteSpace`).
|
||||
- **Array Bounds**: `TMATSectionNumberedArray<T>.SetCount` enforces `_maxNumber` limit if set.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Internal Dependencies
|
||||
- **`System.ComponentModel.DataAnnotations`**: Used for `DescriptionAttribute`, `MaxLengthAttribute`.
|
||||
- **`System.Linq`**: Used for `Enum.GetValues`, `Cast<T>()`, `Any()`, `Take()`, `ToArray()`.
|
||||
- **`System.Text`**: Used for `StringBuilder`.
|
||||
- **`IRIGCh10.AttributeIdentifiers`**: Defines section identifiers (e.g., `"P"` for PCM).
|
||||
- **Nested enums** (e.g., `GeneralTags`, `InformationTags`, `DataSourceIdentificationTags`, `PCMAttributes`, `TypeFormatTags`, `MinorFrameTags`) define attribute names.
|
||||
|
||||
### External Dependencies
|
||||
- **`GeneralInformationGroup`** depends on `Information`, `CommentSection`, `SecuritySection`.
|
||||
- **`PCM`** depends on `PCMTypeFormat`, `MinorFrameSection`.
|
||||
- **`TMATSCreationTest.CreateTMATS()`** depends on `GeneralInformationGroup`, `Storage`, `PCM`, `MinorFrameSection`, `SubframeSync`, `MessageDataType` (not shown in source but referenced).
|
||||
|
||||
### Inferred Usage
|
||||
- The module is used by higher-level classes (e.g., `Storage`, `MessageDataType`) to serialize TMATS sections.
|
||||
- `DescriptionDecoder` and `MaxLengthDecoder` are utility classes used by `TMATSSection<T>`, `TMATSectionNumbered<T>`, and `TMATSectionNumberedArray<T>`.
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **Length Validation Disabled**: Both `SetValueWithLength` methods (`TMATSSection<T>`, `TMATSectionNumbered<T>`) *do not enforce* `MaxLengthAttribute`—the validation code is commented out. This is explicitly noted in comments:
|
||||
> *"maxlength is just a suggestion ..."*
|
||||
> *"apprently maxlength is just a suggestion ..."*
|
||||
- **DataSourceID Uniqueness Check**: `SetDataSourceField` checks for duplicates *only when setting `DataSourceID`*, but the check uses `_datasources.GetValue(number, tag)` *before* the new value is stored, which may not catch all edge cases (e.g., concurrent modifications).
|
||||
- **Indexing Inconsistency**: `TMATSectionNumberedArray<T>.SetValue` uses 1-based indexing for `number`, but internal `_items` list is 0-based (`_items[number - 1]`).
|
||||
- **Date Parsing Strictness**: `GetDate` uses `DateTime.TryParseExact` with `"MM-DD-YYYY"` format and `CultureInfo.InvariantCulture`. Any deviation (e.g., `"11/20/2018"`) will fail.
|
||||
- **Enum Parsing Fallbacks**: Enum property getters (e.g., `PCM.PCMCode`, `PCM.Polarity`) fall back to default values (`null`, `Normal`) if the stored string does not match any `Description`. This may mask serialization errors.
|
||||
- **Missing Section Types**: `SubframeSync`, `MessageDataType`, and `Storage` classes are referenced in `CreateTMATS` but not provided in the source files—behavior is inferred but not verifiable.
|
||||
- **Typo in Enum**: `AttributeIdentifiers.TransmitionAttributes` is misspelled (should be `"Transmission"`).
|
||||
@@ -0,0 +1,199 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/TMATS/DataConversion/DataConversionSection.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/TMATS/DataConversion/TelemetrySection.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/TMATS/DataConversion/CoefficientSection.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/TMATS/DataConversion/Measurand.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/TMATS/DataConversion/OtherInformationSection.cs
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/TMATS/DataConversion/TransducerInformation.cs
|
||||
generated_at: "2026-04-16T03:44:20.663456+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "7f4dfba0264ee789"
|
||||
---
|
||||
|
||||
# Data Conversion Section Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module implements the TMATS (Telemetry and Tracking Attributes Standard) data conversion sections as defined in IRIG Chapter 10 specification (Chapter 9 of the TMATS document). It provides strongly-typed C# classes to represent and serialize various aspects of data conversion metadata—including conversion types, binary formats, polynomial coefficients, measurand descriptions, transducer information, and other measurement-related attributes—into the TMATS packet format used in IRIG 110-04 telemetry standards. These sections enable structured representation of how raw telemetry data is processed, calibrated, and interpreted for engineering analysis.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### Enums
|
||||
|
||||
#### `DataConversionAttributes` (namespace `DTS.Serialization.IRIGCH10.Attributes`)
|
||||
- **`ConversionType`**: Attribute identifier `"DCT"` for specifying the data conversion type.
|
||||
|
||||
#### `ConversionTypes` (namespace `DTS.Serialization.IRIGCH10.Attributes`)
|
||||
- **`None`**: `"NON"` — No conversion applied.
|
||||
- **`PairSets`**: `"PRS"` — Conversion via pair sets.
|
||||
- **`Coefficients`**: `"COE"` — Polynomial coefficients (positive).
|
||||
- **`CoefficientsNegative`**: `"NPC"` — Polynomial coefficients (negative).
|
||||
- **`Derived`**: `"DER"` — Derived channel.
|
||||
- **`Discrete`**: `"DIS"` — Discrete (digital) channel.
|
||||
- **`PCMTime`**: `"PTM"` — PCM time channel.
|
||||
- **`Time1553`**: `"BTM"` — 1553 time channel.
|
||||
- **`DigitalVoice`**: `"VOI"` — Digital voice channel.
|
||||
- **`DigitalVideo`**: `"VID"` — Digital video channel.
|
||||
- **`SpecializedProcessing`**: `"SP"` — Specialized processing.
|
||||
- **`Other`**: `"OTH"` — Other conversion type.
|
||||
|
||||
#### `TelemetryAttributes` (namespace `DTS.Serialization.IRIGCH10.TMATS.DataConversion`)
|
||||
- **`BinaryFormat`**: Attribute identifier `"BFM"` for specifying binary data format.
|
||||
|
||||
#### `BinaryFormats` (namespace `DTS.Serialization.IRIGCH10.TMATS.DataConversion`)
|
||||
- **`Integer`**: `"INT"` — Integer format.
|
||||
- **`UnsignedBinary`**: `"UNS"` — Unsigned binary.
|
||||
- **`SignAndMagnitudeSig`**: `"SIG"` — Sign and magnitude (SIG).
|
||||
- **`SignAndMagnitudeSim`**: `"SIM"` — Sign and magnitude (SIM).
|
||||
- **`OnesCompliment`**: `"ONE"` — One’s complement.
|
||||
- **`TwosCompliment`**: `"TWO"` — Two’s complement.
|
||||
- **`OffsetBinary`**: `"OFF"` — Offset binary.
|
||||
- **`FloatingPoint`**: `"FPT"` — Floating point.
|
||||
- **`BinaryCodedDecimal`**: `"BCD"` — BCD.
|
||||
- **`BitWeight`**: `"BWT"` — Bit weight.
|
||||
- **`Other`**: `"OTH"` — Other format.
|
||||
|
||||
#### `CoefficientsAttributes` (namespace `DTS.Serialization.IRIGCH10.TMATS.DataConversion`)
|
||||
- **`OrderOfCurveFit`**: `"CO\\N"` — Polynomial order *n*.
|
||||
- **`DerivedFromPairSet`**: `"CO1"` — Indicates derivation from pair set.
|
||||
- **`Coefficient0`** to **`Coefficient7`**: `"CO"`, `"CO-1"` … `"CO-7"` — Polynomial coefficients (0th to 7th order).
|
||||
|
||||
#### `MeasurandAttributes` (namespace `DTS.Serialization.IRIGCH10.TMATS.DataConversion`)
|
||||
- **`Description`**: `"MN1"` — Measurand description (max 64 chars).
|
||||
- **`MeasurementAlias`**: `"MNA"` — Alternate name (max 32 chars).
|
||||
- **`ExcitationVoltage`**: `"MN2"` — Sensor excitation voltage in volts (max 10 chars).
|
||||
- **`EngineeringUnits`**: `"MN3"` — Engineering units (max 16 chars).
|
||||
- **`LinkType`**: `"MN4"` — Source data link type (max 3 chars).
|
||||
|
||||
#### `SourceDataTypeLinks` (namespace `DTS.Serialization.IRIGCH10.TMATS.DataConversion`)
|
||||
- **`FM`**: `"ANA"` — Analog (FM).
|
||||
- **`PCM`**: `"PCM"` — PCM.
|
||||
- **`PAM`**: `"PAM"` — PAM.
|
||||
- **`Other`**: `"OTH"` — Other.
|
||||
|
||||
#### `OtherInformationAttributes` (namespace `DTS.Serialization.IRIGCH10.Attributes`)
|
||||
- **`HighMeasurementValue`**: `"MOT1"` — Max engineering value (max 32 chars).
|
||||
- **`LowMeasurementValue`**: `"MOT2"` — Min engineering value (max 32 chars).
|
||||
- **`HighAlertLimitValue`**: `"MOT3"` — High alert limit (max 32 chars).
|
||||
- **`LowAlertLimitValue`**: `"MOT4"` — Low alert limit (max 32 chars).
|
||||
- **`HighWarningLimitValue`**: `"MOT5"` — High warning limit (max 32 chars).
|
||||
- **`LowWarningLimitValue`**: `"MOT6"` — Low warning limit (max 32 chars).
|
||||
- **`SampleRate`**: `"SR"` — Sample rate in samples/sec (max 6 chars).
|
||||
|
||||
#### `TransducerInformation` (namespace `DTS.Serialization.IRIGCH10.TMATS.DataConversion`)
|
||||
- **`MeasurementName`**: `"DCN"` — Measurement name (max 32 chars).
|
||||
- **`Type`**: `"TRD1"` — Sensor type (max 32 chars).
|
||||
- **`ModelNumber`**: `"TRD2"` — Model number (max 32 chars).
|
||||
- **`SerialNumber`**: `"TRD3"` — Serial number (max 32 chars).
|
||||
- **`SecurityClassification`**: `"TRD4"` — Classification code (max 2 chars).
|
||||
- **`OriginationDate`**: `"TRD5"` — Date in `MM-DD-YYYY` format (max 10 chars).
|
||||
- **`RevisionNumber`**: `"TRD6"` — Revision number (max 4 chars).
|
||||
- **`Orientation`**: `"TRD7"` — Physical orientation (max 32 chars).
|
||||
- **`PointOfContactName`**: `"POC1"` — POC name (max 32 chars).
|
||||
- **`PointOfContactAgency`**: `"POC2"` — POC agency (max 48 chars).
|
||||
- **`PointOfContectAddress`**: `"POC3"` — POC address (max 48 chars).
|
||||
- **`PointOfContactTelephone`**: `"POC4"` — POC telephone (max 20 chars).
|
||||
|
||||
#### `ClassificationTypes` (namespace `DTS.Serialization.IRIGCH10.TMATS.DataConversion`)
|
||||
- **`Unclassified`**: `"U"`
|
||||
- **`Confidential`**: `"C"`
|
||||
- **`Secret`**: `"S"`
|
||||
- **`TopSecret`**: `"T"`
|
||||
- **`Other`**: `"O"`
|
||||
|
||||
### Classes
|
||||
|
||||
#### `DataConversionSection`
|
||||
- **Constructor**: `DataConversionSection(int number)`
|
||||
Initializes the section with `AttributeIdentifiers.DataConversionAttributes` and given `number`.
|
||||
- **`SetConversionType(ConversionTypes type)`**:
|
||||
Sets the `"DCT"` attribute to the encoded description of `type` (e.g., `"COE"` for `Coefficients`).
|
||||
|
||||
#### `TelemetrySection`
|
||||
- **Constructor**: `TelemetrySection(int number)`
|
||||
Initializes the section with `AttributeIdentifiers.DataConversionAttributes` and given `number`.
|
||||
- **`SetBinaryFormat(BinaryFormats format)`**:
|
||||
Sets the `"BFM"` attribute to the encoded description of `format` (e.g., `"TWO"` for `TwosCompliment`).
|
||||
|
||||
#### `CoefficientSection`
|
||||
- **Constructor**: `CoefficientSection(int number)`
|
||||
Initializes the section with `AttributeIdentifiers.DataConversionAttributes` and given `number`.
|
||||
- **`OrderOfCurveFit`**: `int?`
|
||||
Gets/sets the `"CO\\N"` attribute (polynomial order *n*).
|
||||
- **`Coefficient0`**: `string`
|
||||
Gets/sets the `"CO"` attribute (0th-order coefficient, e.g., offset).
|
||||
- **`Coefficient1`**: `string`
|
||||
Gets/sets the `"CO-1"` attribute (1st-order coefficient, equivalent to bit weight).
|
||||
|
||||
#### `MeasurandSection`
|
||||
- **Constructor**: `MeasurandSection(int number)`
|
||||
Initializes the section with `AttributeIdentifiers.DataConversionAttributes` and given `number`.
|
||||
- **`Description`**: `string`
|
||||
Gets/sets `"MN1"` — Measurand description.
|
||||
- **`MeasurementAlias`**: `string`
|
||||
Gets/sets `"MNA"` — Alternate name.
|
||||
- **`ExcitationVoltage`**: `string`
|
||||
Gets/sets `"MN2"` — Sensor excitation voltage (volts).
|
||||
- **`EngineeringUnits`**: `string`
|
||||
Gets/sets `"MN3"` — Engineering units.
|
||||
- **`SetLinkType(SourceDataTypeLinks linkType)`**:
|
||||
Sets `"MN4"` to the encoded description of `linkType`.
|
||||
|
||||
#### `OtherInformationSection`
|
||||
- **Constructor**: `OtherInformationSection(int number)`
|
||||
Initializes the section with `AttributeIdentifiers.DataConversionAttributes` and given `number`.
|
||||
- **`HighMeasurementValue`**, **`LowMeasurementValue`**, **`HighAlertLimitValue`**, **`LowAlertLimitValue`**, **`HighWarningLimitValue`**, **`LowWarningLimitValue`**: `string`
|
||||
Gets/sets corresponding `"MOTx"` attributes (engineering unit limits).
|
||||
- **`SampleRate`**: `string`
|
||||
Gets/sets `"SR"` — Sample rate (samples/sec).
|
||||
|
||||
#### `TransducerInformationSection`
|
||||
- **Constructor**: `TransducerInformationSection(int number)`
|
||||
Initializes the section with `AttributeIdentifiers.DataConversionAttributes` and given `number`.
|
||||
- **`MeasurementName`**, **`Type`**, **`ModelNumber`**, **`SerialNumber`**, **`RevisionNumber`**, **`Orientation`**: `string`
|
||||
Gets/sets respective `"DCN"`, `"TRDx"`, `"TRD7"` attributes.
|
||||
- **`SecurityClassification`**: `string`
|
||||
Gets/sets `"TRD4"` — Classification code.
|
||||
- **`SetSecurityClassification(ClassificationTypes type, bool signalClassified, bool measurandClassified)`**:
|
||||
Sets `"TRD4"` to `type` description, optionally appending `"B"` (both), `"R"` (signal only), or `"E"` (measurand only).
|
||||
- **`OriginationDate`**: `DateTime?`
|
||||
Gets/sets `"TRD5"` — Date in `MM-DD-YYYY` format.
|
||||
- **`PointOfContact`**: `POC`
|
||||
Gets/sets POC data via `POC` class (see below).
|
||||
|
||||
#### `POC` (nested class in `TransducerInformationSection`)
|
||||
- **Properties**: `Name`, `Agency`, `Address`, `Telephone` (`string`).
|
||||
- **Constructors**: Parameterized and default.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- All sections inherit from `TMATSSection<T>` and are initialized with `AttributeIdentifiers.DataConversionAttributes`, indicating they belong to the *Data Conversion* TMATS section group.
|
||||
- Attribute values are stored as strings with explicit length encoding via `SetValueWithLength`.
|
||||
- Integer attributes (`OrderOfCurveFit`) use `GetIntOrNull`/`SetIntOrNull`, implying nullable integer handling.
|
||||
- Date values (`OriginationDate`) are serialized in strict `MM-DD-YYYY` format (e.g., `03-15-2023`); parsing is lenient (`DateTime.TryParse`).
|
||||
- Classification codes may be extended with suffixes (`B`, `R`, `E`) depending on `signalClassified`/`measurandClassified` flags.
|
||||
- String attributes have maximum lengths enforced via `[MaxLength]` attributes on enum fields (e.g., `Description` max 64 chars), though enforcement occurs at serialization time via `SetValueWithLength`.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Dependencies *of* this module:
|
||||
- **IRIGCh10.dll**: Provides base infrastructure (`TMATSSection<T>`, `AttributeIdentifiers`, `DescriptionDecoder`).
|
||||
- **System.ComponentModel**: Used for `[Description]` and `[MaxLength]` attributes.
|
||||
- **System.ComponentModel.DataAnnotations**: Used for `[MaxLength]`.
|
||||
|
||||
### Dependencies *on* this module:
|
||||
- Other TMATS section implementations (e.g., `TMATSSection<T>` base class).
|
||||
- Likely consumed by higher-level TMATS packet builders (e.g., `TMATSPacketBuilder`).
|
||||
- `DescriptionDecoder.GetDescription(Enum)` is used extensively to convert enum values to their IRIG-compliant string codes.
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **Typo in POC property**: In `TransducerInformationSection.PointOfContact.get`, `Address` is incorrectly assigned from `PointOfContectAddress` *twice* (should be `PointOfContectAddress` for `Address`, `PointOfContactTelephone` for `Telephone`). This is likely a bug.
|
||||
- **Classification suffix logic**: The `SetSecurityClassification` method appends `"B"`, `"R"`, or `"E"` to the base classification code. This is non-standard and may be proprietary extension; verify against IRIG spec.
|
||||
- **`DerivedFromPairSet` attribute (`CO1`)**: Defined in `CoefficientsAttributes` but has no corresponding property or setter in `CoefficientSection`. Its purpose is unclear from source.
|
||||
- **`SampleRate` max length**: Only 6 characters — may truncate high-precision rates (e.g., `123456` Hz is valid, but `1.23456e5` may exceed limit).
|
||||
- **`OriginationDate` format**: Hardcoded as `MM-DD-YYYY` (e.g., `03-15-2023`). This differs from ISO 8601 and may cause parsing issues in non-US locales.
|
||||
- **No validation on coefficient values**: `Coefficient0`, `Coefficient1`, etc., accept arbitrary strings (including scientific notation), but no validation ensures syntactic correctness.
|
||||
- **`BinaryFormats.SignAndMagnitudeSig` vs `SignAndMagnitudeSim`**: Ambiguous naming (`SIG`/`SIM`) — unclear if these correspond to distinct IRIG codes or are implementation-specific variants.
|
||||
@@ -0,0 +1,74 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/IRIGCH10/Utils/Utils.cs
|
||||
generated_at: "2026-04-16T03:42:52.923027+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "675d2f03b19fde67"
|
||||
---
|
||||
|
||||
# Utils
|
||||
|
||||
## Documentation: `DTS.Serialization.IRIGCH10.Utils.Utils`
|
||||
|
||||
---
|
||||
|
||||
### 1. Purpose
|
||||
|
||||
This module provides low-level utility functions for handling IRIG CH10 (Inter-Range Instrumentation Group Command Handler, Chapter 10) data format conventions. Specifically, it supports conversion of integer values to Binary-Coded Decimal (BCD) representation (for fields like dates), and computation of checksums (8-bit, 16-bit, and 32-bit) as required by the CH10 specification. It also offers bit-level manipulation helpers for packing/unpacking bitfields from `BitArray` objects—common when serializing/deserializing packet headers and metadata fields.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
All members are `static` and defined in the `abstract` class `Utils`. No public constructors or instance members exist.
|
||||
|
||||
| Method | Signature | Behavior |
|
||||
|--------|-----------|----------|
|
||||
| `GetBCDBytes` | `public static byte[] GetBCDBytes(int value)` | Converts an integer `value` (0–9999) into a 2-byte BCD representation (least significant digit in lower nibble of byte 0). Throws `ArgumentOutOfRangeException` if `value` is outside [0, 9999]. |
|
||||
| `GetCheckSum8` | `public static ushort GetCheckSum8(byte[] bytes)` | Computes an 8-bit checksum by summing all bytes in `bytes` and returning the low 16 bits of the sum (i.e., `sum & 0xFFFF`). No padding or alignment assumptions. |
|
||||
| `GetCheckSum16` | `public static ushort GetCheckSum16(byte[] bytes)` | Computes a 16-bit checksum per CH10 spec: interprets `bytes` as an array of `ushort` (little-endian, via `Buffer.BlockCopy`) and sums all `ushort` values. **Requires** `bytes.Length` to be even; asserts this via `Trace.Assert`. |
|
||||
| `GetCheckSum32` | `public static uint GetCheckSum32(byte[] bytes)` | Computes a 32-bit checksum per CH10 spec: interprets `bytes` as an array of `uint` (little-endian) and sums all `uint` values. **Requires** `bytes.Length` to be divisible by 4; asserts this via `Trace.Assert`. |
|
||||
| `BitArrayToInt32` | `public static int BitArrayToInt32(BitArray ba, int startIndex, int endIndex)` | Extracts bits from `ba` between `startIndex` and `endIndex` (inclusive), interpreting them as a little-endian integer (bit 0 = LSB). Returns an `int` (up to 32 bits). |
|
||||
| `SetBits` | `public static void SetBits(BitArray b, uint value, int startIndex, int endIndex)` | Writes the least-significant bits of `value` (covering `(endIndex - startIndex + 1)` bits) into `b`, starting at `startIndex`. Bits are copied in little-endian order (bit 0 of `value` → `b[startIndex]`). |
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
|
||||
- **BCD Range**: `GetBCDBytes` enforces `0 ≤ value ≤ 9999`. Values outside this range throw `ArgumentOutOfRangeException`.
|
||||
- **Checksum Input Length**:
|
||||
- `GetCheckSum16` requires `bytes.Length % 2 == 0`.
|
||||
- `GetCheckSum32` requires `bytes.Length % 4 == 0`.
|
||||
- These are enforced via `Trace.Assert`, which may be compiled out in Release builds—**no runtime exception is thrown** if the invariant is violated in non-Debug builds.
|
||||
- **Bit Index Bounds**: `BitArrayToInt32` and `SetBits` assume `0 ≤ startIndex ≤ endIndex < ba.Length` (or `b.Length`). No explicit bounds checking is performed; out-of-range indices will cause `IndexOutOfRangeException` at runtime.
|
||||
- **Endianness**: All multi-byte integer interpretations (via `Buffer.BlockCopy` into `ushort[]`/`uint[]`) assume **little-endian byte order**, consistent with .NET’s default on most platforms.
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
|
||||
**Imports/Usings**:
|
||||
- `System`
|
||||
- `System.Collections` (`BitArray`)
|
||||
|
||||
**Used By**:
|
||||
- Other modules in `DTS.Serialization.IRIGCH10` (inferred from namespace), particularly those handling packet serialization/deserialization (e.g., header construction, data packet checksumming, date/time field encoding).
|
||||
|
||||
**Used For**:
|
||||
- Encoding/decoding BCD fields (e.g., timestamps, counters).
|
||||
- Computing checksums for CH10 packet headers (`GetCheckSum16`) and data payloads (`GetCheckSum32`).
|
||||
- Bit-level manipulation of packet fields (e.g., flags, variable-length integers).
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
|
||||
- **`Trace.Assert` is not a runtime guard**: In non-Debug builds, failed assertions in `GetCheckSum16` and `GetCheckSum32` will not throw exceptions—invalid input lengths may cause silent corruption or incorrect checksums. Callers must ensure input alignment themselves.
|
||||
- **BCD encoding is fixed to 4 decimal digits**: `GetBCDBytes` only supports values up to 9999 (2 bytes). Larger values require multiple calls or a different approach (not provided here).
|
||||
- **Little-endian assumption**: `GetCheckSum16`/`GetCheckSum32` rely on `Buffer.BlockCopy` interpreting bytes as little-endian `ushort`/`uint`. This is platform-dependent on .NET (true on x86/x64), but may break on big-endian systems.
|
||||
- **No overflow handling in checksums**: Sums wrap around modulo 2¹⁶ (for `ushort`) or 2³² (for `uint`), per CH10 spec—but this is implicit, not documented in code.
|
||||
- **`SetBits` uses `BitConverter.GetBytes(value)`**: This assumes little-endian layout for `value`, and only the lowest `(endIndex - startIndex + 1)` bits are copied. If `value` has more bits set than `endIndex - startIndex + 1`, higher bits are silently ignored. No validation ensures `value` fits the bit range.
|
||||
- **`BitArrayToInt32` uses LSB-first indexing**: Bit 0 of the result corresponds to `ba[startIndex]`, not `ba[endIndex]`. This matches CH10’s typical bit numbering but may be counterintuitive.
|
||||
|
||||
None identified beyond the above.
|
||||
201
enriched-qwen3-coder-next/Common/DTS.Common.Serialization/Iso.md
Normal file
201
enriched-qwen3-coder-next/Common/DTS.Common.Serialization/Iso.md
Normal file
@@ -0,0 +1,201 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/Iso/Iso.File.Test.ExtraProperty.cs
|
||||
- Common/DTS.Common.Serialization/Iso/Iso.File.cs
|
||||
- Common/DTS.Common.Serialization/Iso/Iso.File.Test.Object.cs
|
||||
- Common/DTS.Common.Serialization/Iso/Iso.File.Test.cs
|
||||
generated_at: "2026-04-16T03:35:46.255556+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "353d00996507afad"
|
||||
---
|
||||
|
||||
# Documentation: `DTS.Serialization.Iso.File` Module
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module implements the ISO 14967-compliant serialization format for test data, specifically for crash test and impact testing scenarios. It provides structured representations of test metadata, test objects (e.g., dummies, barriers), channels (sensor data), and custom properties, enabling export of test results in a standardized text-based format. The module resides within the `DTS.Serialization.Iso` namespace and extends a base `Serialization.File` class, integrating with a proprietary test plan abstraction (`Common.ISO.TestPlan`) to populate ISO fields and delegate writing to a dedicated `Writer` class.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### `DTS.Serialization.Iso.File`
|
||||
|
||||
- **`File(Common.ISO.TestPlan testplan)`**
|
||||
Constructor. Initializes a new ISO file instance with the provided test plan. Calls `base("ISO")`.
|
||||
|
||||
- **`bool ExportSummaryReport { get; set; } = false`**
|
||||
Controls whether a summary report is included in the export.
|
||||
|
||||
- **`bool UseZeroForUnfiltered { get; set; } = false`**
|
||||
When `true`, unfiltered channel data is exported as `0` instead of omitting it.
|
||||
|
||||
- **`bool UseIsoCodeFilterMapping { get; set; }`**
|
||||
When `true`, the ISO code for a filter is determined by the software filter mapping for the channel.
|
||||
|
||||
- **`bool FilteredExport { get; set; } = false`**
|
||||
Indicates whether the export is filtered.
|
||||
|
||||
- **`bool ExportISOChannelName { get; set; } = false`**
|
||||
Controls whether the ISO channel name is exported.
|
||||
|
||||
- **`void AddChannel(string dasserial, int moduleNumber, int number, string description, FilteredData data)`**
|
||||
Delegates to the exporter (`Writer`) to add a channel with the specified metadata and data.
|
||||
|
||||
- **`void ApplyTestPlan(Serialization.Test test)`**
|
||||
Populates the `TestInstance` properties by iterating over `Common.ISO.TestPlan.IsoFields` enum values and mapping each to corresponding fields on `TestInstance`. Special handling includes:
|
||||
- Parsing `Date` with fallback to `test.InceptionDate`.
|
||||
- Converting `ExtraProperties` dictionary to `List<ExtraProperty>`.
|
||||
- Using `"NOVALUE"` for null/empty values via `GetFieldString`.
|
||||
- Throws `NotSupportedException` for unsupported fields.
|
||||
|
||||
- **`IWriter<Serialization.Test> Exporter { get; }`**
|
||||
Lazily initializes and returns a `Writer` instance configured with current settings (`UseZeroForUnfiltered`, `UseIsoCodeFilterMapping`, etc.). Throws a wrapped `Exception` on failure.
|
||||
|
||||
- **`Test TestInstance { get; }`**
|
||||
Returns the `Test` instance associated with this file. Initialized with a default `Test()`.
|
||||
|
||||
- **`static string TestFileExtension { get; }`**
|
||||
Returns `".mme"` (file extension for serialized test data).
|
||||
|
||||
- **`static string ChannelFileExtension { get; }`**
|
||||
Returns `".chn"` (file extension for serialized channel data).
|
||||
|
||||
- **`Common.ISO.TestPlan GetTestPlan()`**
|
||||
Returns the `_testPlan` field passed at construction.
|
||||
|
||||
### `DTS.Serialization.Iso.File.Test`
|
||||
|
||||
- **`string DataFormatEditionNumber { get; set; }`**
|
||||
Default: `"1.6"`. Represents the ISO data format edition.
|
||||
|
||||
- **`string LaboratoryName`, `LaboratoryContactName`, `LaboratoryContactPhone`, etc.**
|
||||
Standard ISO metadata fields (e.g., lab name, contact info, test reference numbers). All are `string` properties with associated label constants (e.g., `LaboratoryNameLabel = "Laboratory name"`).
|
||||
|
||||
- **`string CustomerName`, `CustomerTestReferenceNumber`, `CustomerProjectReferenceNumber`, etc.**
|
||||
Customer-related metadata fields.
|
||||
|
||||
- **`string TestEngineerName`, `TestEngineerPhone`, `TestEngineerFax`, `TestEngineerEmail`**
|
||||
Test engineer contact fields.
|
||||
|
||||
- **`string Title { get; set; }`**
|
||||
Title of the test. If `null` or `"NOVALUE"`, defaults to `test.Id` in `ApplyTestPlan`.
|
||||
|
||||
- **`string NumberOfMedia { get; set; }`**
|
||||
Default: `"1/1"`.
|
||||
|
||||
- **`string Timestamp { get; set; }`**
|
||||
Default: current time in `"yyyy-MM-dd HH:mm:ss"` format.
|
||||
|
||||
- **`string TestComment { get; set; }`**
|
||||
Comment field for the test.
|
||||
|
||||
- **`string Type { get; set; }`**
|
||||
Type of the test.
|
||||
|
||||
- **`DateTime Date { get; set; }`**
|
||||
Date of the test. Initialized to `DateTime.Now`.
|
||||
|
||||
- **`string Subtype { get; set; }`**
|
||||
Subtype of the test.
|
||||
|
||||
- **`string Regulation { get; set; }`**
|
||||
Regulatory framework.
|
||||
|
||||
- **`string ReferenceTemperature { get; set; }`**
|
||||
Reference temperature.
|
||||
|
||||
- **`string RelativeAirHumidity { get; set; }`**
|
||||
Relative air humidity.
|
||||
|
||||
- **`int NumberOfTestObjects { get; }`**
|
||||
Returns `Objects.Count`.
|
||||
|
||||
- **`List<Object> Objects { get; set; }`**
|
||||
List of test objects (e.g., dummies, barriers). Initialized to empty list.
|
||||
|
||||
- **`List<Channel> Channels { get; set; }`**
|
||||
List of channels (defined in other files, not included here).
|
||||
|
||||
- **`List<ExtraProperty> ExtraProperties { get; set; }`**
|
||||
List of custom key-value properties. Initialized to empty list.
|
||||
|
||||
- **`string ToString()`**
|
||||
Generates the ISO header section of the test file, including all metadata fields and extra properties, formatted as `label: value` lines. Uses `GetFieldString` to handle uninitialized values as `"NOVALUE"`.
|
||||
|
||||
### `DTS.Serialization.Iso.File.Test.ExtraProperty`
|
||||
|
||||
- **`ExtraProperty(string key, string value)`**
|
||||
Constructor. Initializes `_Key` and `_Value` with provided values.
|
||||
|
||||
- **`string Key { get; set; }`**
|
||||
Gets or sets the property key. Returns `null` if not initialized.
|
||||
|
||||
- **`string Value { get; set; }`**
|
||||
Gets or sets the property value. Returns `null` if not initialized.
|
||||
|
||||
### `DTS.Serialization.Iso.File.Test.Object`
|
||||
|
||||
- **`string[] Comments { get; set; }`**
|
||||
Array of comment strings.
|
||||
|
||||
- **`string Name`, `Type`, `Number`, `Velocity`, `Mass`, `Position`, `TestObjectImpactSide`, `Class`, `Code`, `Offset`, `BarrierWidth`, `BarrierHeight`, `YawAngle`, `ReferenceSystem`, `OriginX`, `OriginY`, `OriginZ`, `NumberOfLoadcells`**
|
||||
All are `string` properties with associated label constants (e.g., `NameLabel = "Name of test object #"`). Default values: `"0.0"` for `Velocity`, `""` for `Mass`, `"?"` for `Position`.
|
||||
|
||||
- **`int MmeNumber { get; set; }`**
|
||||
Internal MME number for the object. Default: `-1`.
|
||||
|
||||
- **`string TestObject { get; set; }`**
|
||||
Placeholder field (label: `"Test Object #"`).
|
||||
|
||||
- **`List<ExtraProperty> ExtraProperties { get; set; }`**
|
||||
List of custom properties for this object. Initialized to empty list.
|
||||
|
||||
- **`string ToString()`**
|
||||
Generates the ISO representation of the test object, including comments, metadata, and conditional barrier-specific fields (if `Type == "B"`). Uses `GetFieldString` for value extraction. Special handling for `Position` and `TestObjectImpactSide`: if not `"NOVALUE"` or empty, extracts substring before `'-'` (e.g., `"L-1"` → `"L"`).
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **`NoValue` constant**: The string `"NOVALUE"` is used to represent missing or uninitialized field values in the output.
|
||||
- **Label formatting**: All labels are right-padded to `SeparatorOffset` (28 characters) before appending `Separator` (`":"`).
|
||||
- **`GetFieldString` behavior**: Returns `"NOVALUE"` if the extractor returns `null`, `string.Empty`, or throws an exception.
|
||||
- **`Property<T>` initialization**: All properties use `Property<T>` wrappers with unique keys (namespace-qualified), default values, and immutability flags (`true` for statics like `TestFileExtension`, `false` for instance fields).
|
||||
- **`ExtraProperties` handling**: In `ApplyTestPlan`, `ExtraProperties` from `TestPlan` (a dictionary) is converted to a list of `ExtraProperty` instances.
|
||||
- **`Date` parsing**: If `DateTime.TryParse` fails for `Date` field, falls back to `test.InceptionDate`.
|
||||
- **`Type == "B"` condition**: Barrier-specific fields (`BarrierWidth`, `OriginX`, etc.) are only included in `Object.ToString()` if `Type == "B"`.
|
||||
- **`Position`/`TestObjectImpactSide` substring extraction**: Only performed if value is not `"NOVALUE"` and not empty; uses `IndexOf('-') - 1` as end index.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
- **Imports/Usings**:
|
||||
- `DTS.Common.Utilities` and `DTS.Common.Utilities.DotNetProgrammingConstructs` (for `Property<T>`, `Exceptional` base class).
|
||||
- `DTS.Serialization.Iso.Report` (for `IWritable<Test>` and `IWriter<Test>`).
|
||||
- `System`, `System.Collections.Generic`, `System.Linq`, `System.Text`, `System.Threading.Tasks`.
|
||||
|
||||
- **Key Dependencies**:
|
||||
- `Common.ISO.TestPlan`: Provides test metadata via `GetField(IsoFields)` and `ExtraProperties` dictionary.
|
||||
- `Serialization.File`: Base class for file serialization.
|
||||
- `IWritable<Test>`: Interface implemented by `File`.
|
||||
- `IWriter<Test>`: Writer interface (implemented by `Writer` class, instantiated in `Exporter`).
|
||||
- `FilteredData`: Type for channel data (used in `AddChannel`).
|
||||
|
||||
- **Depended Upon**:
|
||||
- `Writer` class (inferred from `Exporter` property and `AddChannel` method).
|
||||
- Likely consumed by higher-level serialization logic (e.g., export UI or batch processor).
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **Substring index risk in `Object.ToString()`**: The `Position` and `TestObjectImpactSide` substring extraction (`Substring(0, IndexOf('-') - 1)`) will throw `ArgumentOutOfRangeException` if the value contains no `'-'` or if `'-'` is at index `0` or `1`. This is not guarded against in the source.
|
||||
|
||||
- **`Timestamp` default is non-deterministic**: `Timestamp` defaults to `DateTime.Now`, which may cause non-reproducible exports if not explicitly set.
|
||||
|
||||
- **`ExtraProperties` key collision**: If `ExtraProperties` from `TestPlan` contains duplicate keys, the last one wins in the list (no explicit deduplication).
|
||||
|
||||
- **`TestInstance` is lazily initialized but not thread-safe**: The `TestInstance` property returns a shared instance; concurrent modifications could cause race conditions.
|
||||
|
||||
- **`NoValue` is hardcoded**: `"NOVALUE"` is used as a sentinel, but there is no validation to prevent user data from accidentally using this string.
|
||||
|
||||
- **`ApplyTestPlan` throws `NotSupportedException`**: Any unhandled `IsoFields` enum value causes a hard failure. This may break if the enum is extended.
|
||||
|
||||
- **`Property<T>` null handling**: Properties with `IsValueInitialized == false` return `null` for reference types (e.g., `string`, `List<T>`), but `GetFieldString` treats `null` as `"NOVALUE"`. This is consistent but requires care when checking for presence.
|
||||
|
||||
- **No explicit validation**: No validation is performed on field values (e.g., `Velocity` is a string but expected to be numeric; `Position` codes like `"L-1"` are parsed but not validated).
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/Iso/Report/SummaryReport.cs
|
||||
- Common/DTS.Common.Serialization/Iso/Report/ChannelData.cs
|
||||
generated_at: "2026-04-16T03:40:44.805086+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "6a29f80fb642a4d0"
|
||||
---
|
||||
|
||||
# Report
|
||||
|
||||
## Documentation: Summary Report Serialization Module
|
||||
|
||||
### 1. Purpose
|
||||
This module provides functionality to generate and output a standardized text-based summary report for ISO test data. It aggregates channel metadata (e.g., ISO code, name, filter class, EIDs, data flags) from a `Test` object into a structured report format, primarily for use in import workflows (e.g., test setup reconciliation or audit trails). The report is serialized to a file named `TestNo_FilterList.txt` in a specified directory. It is part of the `DTS.Serialization.Iso.Report` namespace and serves as a bridge between internal test data structures and external systems expecting this specific textual format.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
#### `SummaryReport` class
|
||||
- **`public static SummaryReport CreateSummaryReport(Test test)`**
|
||||
Factory method that constructs a `SummaryReport` instance by extracting channel data from the provided `test` object. Internally calls `AddChannels` to populate channel data.
|
||||
- *Returns*: A fully populated `SummaryReport` instance.
|
||||
|
||||
- **`public string GetLines()`**
|
||||
Generates the full report content as a single string.
|
||||
- *Returns*: A multi-line string where the first line is `"Number of channels :XXX / / / / /"` (with zero-padded channel count), followed by one line per channel (see `ChannelData.GetLine()`).
|
||||
|
||||
- **`public static void OutputToPath(string path, SummaryReport summary)`**
|
||||
Writes the report content (from `summary.GetLines()`) to a file named `TestNo_FilterList.txt` in the directory specified by `path`.
|
||||
- *Throws*: May throw `IOException`, `UnauthorizedAccessException`, or other exceptions from `File.WriteAllText`.
|
||||
|
||||
- **`protected void AddChannels(Test.Module.Channel[] channels)`**
|
||||
Adds channel data to the internal `_channels` list, converting each `Test.Module.Channel` to a `ChannelData` via `ChannelData.CreateChannel`. Channels are sorted by `ChannelNumber` (ascending) after insertion.
|
||||
- *Note*: This method is `protected`, so it is only callable from within `SummaryReport` or derived classes.
|
||||
|
||||
#### `ChannelData` class *(internal)*
|
||||
- **`public string GetLine()`**
|
||||
Returns a single formatted line for this channel in the report.
|
||||
- *Format*: `"Name of channel XXX :<ISOCode> / <ChannelName> / <SAEFilterClass> / <SetupEID> / <DataCollectionEID> / <DataFlagInt>"`, where `XXX = ChannelNumber + 1` (1-indexed, zero-padded to 3 digits).
|
||||
|
||||
- **`public static ChannelData CreateChannel(Test.Module.Channel channel)`**
|
||||
Factory method that constructs a `ChannelData` instance from a `Test.Module.Channel`.
|
||||
- *Behavior*:
|
||||
- For `AnalogInputChannel` instances, extracts `IsoCode`, `IsoChannelName`, and `SoftwareFilter` (spaces removed).
|
||||
- For non-`AnalogInputChannel` types, `ISOCode` and `ChannelName` default to `string.Empty`; `SAEFilterClass` defaults to `string.Empty`.
|
||||
- Maps `channel.AbsoluteDisplayOrder` → `ChannelNumber`, `channel.DataCollectionEID` → `DataCollectionEID`, `channel.SetupEID` → `SetupEID`, `channel.DataFlag` → `DataFlag` (cast to `DataFlag` enum).
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
- **Channel ordering**: Channels in the report are sorted by `ChannelNumber` (ascending), as enforced by `_channels.Sort(...)` in `AddChannels`.
|
||||
- **Channel numbering**: The channel index in the report header line (`XXX`) is `ChannelNumber + 1`, making it 1-indexed (e.g., `ChannelNumber=0` → `001`).
|
||||
- **Fixed header format**: The first line of the report always follows the pattern:
|
||||
`"Number of channels :{count:000} / / / / /"`, with exactly 3 digits for the count and 5 trailing ` / ` segments (the last 4 are empty).
|
||||
- **Channel line format**: Each channel line uses the literal `"Name of channel"` prefix and exactly 6 ` / `-separated fields: `ISOCode`, `ChannelName`, `SAEFilterClass`, `SetupEID`, `DataCollectionEID`, and `(int)DataFlag`.
|
||||
- **Filter class normalization**: `SAEFilterClass` is derived from `analog.SoftwareFilter` with all spaces removed (via `Replace(" ", "")`).
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
- **Internal types used**:
|
||||
- `Test` (namespace `DTS.Test` or similar; imported implicitly via `Test.Module.Channel`)
|
||||
- `Test.Module.Channel` (base type)
|
||||
- `Test.Module.AnalogInputChannel` (derived type; only this subtype is handled specially)
|
||||
- `DataFlag` enum (from `DTS.Common` namespace)
|
||||
- **External dependencies**:
|
||||
- `System.Collections.Generic` (`List<T>`)
|
||||
- `System.Text` (`StringBuilder`)
|
||||
- `System.IO` (`File.WriteAllText`, `Path.Combine`)
|
||||
- **Depended upon by**:
|
||||
- Likely consumed by UI or workflow components (e.g., import wizard) as inferred from comments referencing internal cases. No explicit callers are visible in the source.
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
- **Non-`AnalogInputChannel` handling**: For non-`AnalogInputChannel` instances (e.g., digital channels), `ISOCode`, `ChannelName`, and `SAEFilterClass` will be empty strings. This may produce lines like `"Name of channel 001 : / / / EID1 / EID2 / 0"`.
|
||||
- **`DataFlag` enum cast**: `channel.DataFlag` is cast directly to `DataFlag` (e.g., `(DataFlag)channel.DataFlag`). If `channel.DataFlag` is an `int` with values outside the `DataFlag` enum’s defined range, this may yield undefined or unexpected values.
|
||||
- **Path handling**: `OutputToPath` uses `Path.Combine(path, "TestNo_FilterList.txt")`, so `path` must be a valid directory path (not a file path). Passing a file path will cause an `ArgumentException` or `IOException`.
|
||||
- **No validation on `Test` object**: `CreateSummaryReport` does not validate that `test.Channels` is non-null. If `test.Channels` is `null`, `AddChannels([.. test.Channels])` will throw a `NullReferenceException`.
|
||||
- **`protected` method**: `AddChannels` is not public, so external code cannot manually populate channels—only via `CreateSummaryReport`.
|
||||
- **Hardcoded filename**: The output filename `"TestNo_FilterList.txt"` is hardcoded in `OutputToPath`, with no configurability.
|
||||
- **No encoding specification**: `File.WriteAllText` uses UTF-8 *without BOM* by default in .NET 5+, but this is not explicitly stated in the source.
|
||||
@@ -0,0 +1,83 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/Properties/AssemblyInfo.cs
|
||||
- Common/DTS.Common.Serialization/Properties/Settings1.Designer.cs
|
||||
generated_at: "2026-04-16T03:37:53.704211+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "56e1c9c1d32b363c"
|
||||
---
|
||||
|
||||
# Properties
|
||||
|
||||
## Documentation: `DTS.Common.Serialization` Assembly
|
||||
|
||||
---
|
||||
|
||||
### 1. Purpose
|
||||
This module provides shared serialization-related infrastructure for the DTS system, primarily encapsulating application settings and metadata for the serialization assembly. Based on the source files, it does **not** contain any serialization logic (e.g., JSON/XML converters, serializers, or deserializers) itself. Instead, it defines a strongly-typed settings class (`Settings1`) for user- and application-scoped configuration values—particularly those related to TDM (Test Data Manager) file paths, default time ranges, and last-used values for TSV export/import UI state—and exposes assembly-level metadata (title, version, COM visibility). Its role is to centralize configuration state and assembly identity, likely consumed by other modules that perform actual data serialization/deserialization.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
#### `DTS.Serialization.Properties.Settings1`
|
||||
A strongly-typed settings class derived from `System.Configuration.ApplicationSettingsBase`. It exposes the following properties:
|
||||
|
||||
| Property | Type | Scope | Default Value | Description |
|
||||
|---------|------|-------|---------------|-------------|
|
||||
| `TDMFolder` | `string` | User-scoped | `".\\Data\\TDM CFC1000"` | Path to the TDM data folder. |
|
||||
| `DefaultStart` | `double` | User-scoped | `-500` | Default start time (likely in milliseconds or seconds) for time-range operations. |
|
||||
| `DefaultStop` | `double` | User-scoped | `500` | Default stop time (aligned with `DefaultStart`). |
|
||||
| `TSVPOCNameLastUsed` | `string` | User-scoped | `"#NOVALUE"` | Last-used point-of-contact name in TSV export/import workflows. |
|
||||
| `TSVPOCPhoneAndEmailLastUsed` | `string` | User-scoped | `"#NOVALUE"` | Last-used POC contact info in TSV workflows. |
|
||||
| `TSVDataTypeLastUsed` | `string` | User-scoped | `"Converted"` | Last-used data type selection (e.g., raw, converted) in TSV workflows. |
|
||||
| `TSVLabNameLastUsed` | `string` | User-scoped | `"#NOVALUE"` | Last-used lab name in TSV workflows. |
|
||||
| `TSVTestObjectLastUsed` | `string` | User-scoped | `"#NOVALUE"` | Last-used test object identifier in TSV workflows. |
|
||||
| `TSVTestTypeLastUsed` | `string` | User-scoped | `"#NOVALUE"` | Last-used test type in TSV workflows. |
|
||||
| `TableHeader` | `System.Drawing.Color` | Application-scoped | `RGB(215, 225, 255)` | Background color for table headers (read-only). |
|
||||
| `AlternatingRow` | `System.Drawing.Color` | User-scoped | `RGB(238, 242, 255)` | Background color for alternating table rows. |
|
||||
|
||||
- **Static Property**:
|
||||
`public static Settings1 Default { get; }`
|
||||
Returns the singleton instance of `Settings1`, thread-safe via `ApplicationSettingsBase.Synchronized`.
|
||||
|
||||
> **Note**: No public methods beyond property getters/setters are defined in this assembly. No serialization/deserialization functions are present.
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
|
||||
- `Settings1.Default` is a singleton: always returns the same instance (synchronized for thread safety).
|
||||
- `TableHeader` is **read-only** (application-scoped); attempts to set it via `set` will fail at runtime (no setter defined).
|
||||
- All string settings use `"#NOVALUE"` as a sentinel for "unset" or "no previous value".
|
||||
- `TDMFolder` defaults to a relative path (`".\\Data\\TDM CFC1000"`), implying the application expects a specific directory structure.
|
||||
- Time range defaults (`DefaultStart`, `DefaultStop`) are symmetric around zero (`-500` to `500`), suggesting a centered time window (e.g., ±500 ms).
|
||||
- Settings are persisted per-user (user-scoped) except `TableHeader`, which is per-application.
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
|
||||
#### Dependencies *of* this module:
|
||||
- `System.Configuration` (for `ApplicationSettingsBase`, `UserScopedSettingAttribute`, etc.)
|
||||
- `System.Drawing` (for `System.Drawing.Color`)
|
||||
- `System.Runtime.CompilerServices` and `System.CodeDom.Compiler` (for generated-code attributes)
|
||||
|
||||
#### Dependencies *on* this module:
|
||||
- Other modules in the DTS system likely reference this assembly to access `Settings1.Default` for configuration persistence (e.g., UI forms that save/load TSV export options or TDM paths).
|
||||
- No direct evidence of this module consuming *other* serialization logic—its name (`DTS.Common.Serialization`) may be misleading; it is primarily a settings container.
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
|
||||
- **Misleading assembly name**: Despite being named `DTS.Common.Serialization`, this assembly contains **no serialization logic** (no `ISerializer`, `JsonSerializer`, etc.). It is a configuration/settings module.
|
||||
- **Hardcoded paths**: `TDMFolder` uses a Windows-style relative path (`".\\Data\\TDM CFC1000"`), which may break on non-Windows platforms or if the directory structure changes.
|
||||
- **Sentinel values**: `"#NOVALUE"` is used as a placeholder for unset string settings. Consumers must explicitly check for this value instead of assuming `null` or `string.Empty`.
|
||||
- **Color format**: Colors are defined as comma-separated RGB strings in attributes (e.g., `"215, 225, 255"`), but `System.Drawing.Color` parsing is implicit—no validation is visible in this file.
|
||||
- **Thread safety**: While `Synchronized()` is used, `Settings1` is mutable (most properties have setters). Concurrent writes to user-scoped settings may cause race conditions.
|
||||
- **Auto-generated file**: `Settings1.Designer.cs` is auto-generated; manual edits will be overwritten. Changes should be made in the designer or via `.settings` files.
|
||||
- **Versioning**: Assembly version `1.06.0081` suggests a long-lived module; ensure backward compatibility if settings evolve (e.g., new keys added in future versions).
|
||||
|
||||
None identified beyond the above.
|
||||
187
enriched-qwen3-coder-next/Common/DTS.Common.Serialization/RDF.md
Normal file
187
enriched-qwen3-coder-next/Common/DTS.Common.Serialization/RDF.md
Normal file
@@ -0,0 +1,187 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/RDF/RDF.File.cs
|
||||
- Common/DTS.Common.Serialization/RDF/RDF.File.Writer.cs
|
||||
generated_at: "2026-04-16T03:40:00.442802+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "abee1ca96445ca58"
|
||||
---
|
||||
|
||||
# RDF.File Module Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module implements serialization and deserialization logic for Toyota RDF (Rack Data Format) files—a proprietary binary file format used to export test data from DTS systems for Toyota compliance. It defines the `File` class (a concrete implementation of `Serialization.File`) that represents an RDF file and its associated metadata, and the nested `Writer` class responsible for writing test data (`Test`) to disk in the RDF format. The module supports filtering, linearization, and ISO-compliant naming conventions, and is tightly coupled with ISO test plan metadata and DAS hardware configuration.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### `DTS.Serialization.RDF.File`
|
||||
|
||||
- **Constructor**
|
||||
`public File(Common.ISO.TestPlan plan)`
|
||||
Initializes a new `File` instance with the provided `TestPlan`. Calls `base("RDF")` to set the format name.
|
||||
|
||||
- **Properties**
|
||||
- `public static string Extension => ".001"`
|
||||
Returns the fixed file extension for RDF files.
|
||||
- `public bool UseZeroForUnfiltered { get; set; } = false`
|
||||
Controls whether unfiltered data points are written as zero (instead of original ADC values) during export.
|
||||
- `public bool FilteredExport { get; set; } = false`
|
||||
Enables filtering of data during export (behavior depends on downstream `Writer` logic).
|
||||
- `public IWriter<Test> Exporter { get; }`
|
||||
Lazily constructs and returns a `Writer` instance, passing `UseZeroForUnfiltered`, `FilteredExport`, and `_testPlan` to it. Sets `Writer.WriterParent = this` to enable access to EU data.
|
||||
|
||||
- **EU Data Accessors (override)**
|
||||
- `public override void SetEUData(string channelID, FilteredData fd)`
|
||||
Stores filtered EU data for a channel in the internal `_EUUnfilteredDataForLinearizedChannels` dictionary.
|
||||
- `public override FilteredData GetEUData(string channelID)`
|
||||
Retrieves stored EU data for a given `channelID`.
|
||||
|
||||
### `DTS.Serialization.RDF.File.Writer`
|
||||
|
||||
- **Constructor**
|
||||
`internal Writer(File fileType, int encoding)`
|
||||
Internal constructor; initializes base `Writer<File>` with the parent `File` and encoding.
|
||||
|
||||
- **Properties**
|
||||
- `public File WriterParent { get; set; }`
|
||||
Reference to the parent `File` instance (used to access EU data).
|
||||
- `public TestPlan TestPlan { get; set; }`
|
||||
ISO `TestPlan` used for metadata (e.g., test object numbering).
|
||||
- `public string ExtensionPrefix { get; set; } = string.Empty`
|
||||
Optional prefix appended to the filename before the `.001` extension.
|
||||
- `public bool UseZeroForUnfiltered { get; set; }`
|
||||
Mirrors the parent `File.UseZeroForUnfiltered`.
|
||||
- `public bool FilteredExport { get; set; }`
|
||||
Mirrors the parent `File.FilteredExport`.
|
||||
- `public bool UseIsoCodeForDiadem200 { get; set; }`
|
||||
Unused in current implementation (commented out in usage).
|
||||
|
||||
- **Methods**
|
||||
- `public void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)`
|
||||
Convenience overload of `Write(...)` with simplified parameters; delegates to the full 18-parameter overload with `null` for optional event handlers and data folder.
|
||||
|
||||
- `public void Write(string pathname, string id, string dataFolder, Test test, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Test.Module.Channel tmChannel, int channelNumber, BeginEventHandler beginEventHandler, CancelEventHandler cancelEventHandler, EndEventHandler endEventHandler, TickEventHandler tickEventHandler, ErrorEventHandler errorEventHandler, CancelRequested cancelRequested, double minStartTime, int dataCollectionLength)`
|
||||
Primary export method.
|
||||
- Validates/normalizes `id`: strips `" RunTest"` or `" Checkout"` suffixes if present; falls back to `test.Id` if `id` lacks these suffixes.
|
||||
- Truncates `id` to `MAX_TEST_NAME_LENGTH` (8 chars) implicitly via filename construction.
|
||||
- Writes RDF file to `{pathname}/{id}.001`.
|
||||
- Calls `WriteTestInfo(...)` and `WriteChannelInfo(...)` to serialize headers and data.
|
||||
- Handles exceptions via event handlers or rethrows.
|
||||
|
||||
- `public void Initialize(...)`
|
||||
Empty stub; no-op.
|
||||
|
||||
- `protected void WriteTestInfo(BinaryWriter fileWriter, Test test, string testId, TickEventHandler tickEventHandler, string dataFolder)`
|
||||
Writes an 80-byte header record containing:
|
||||
- `testId` (padded/truncated to 8 chars)
|
||||
- Number of files (hardcoded to `"1"`)
|
||||
- File number (`" 1"`)
|
||||
- Number of channels (`test.Channels.Count`, left-padded to 3 chars)
|
||||
- Timestamp (MM, DD, YY, HH, MM)
|
||||
- 53 bytes of padding.
|
||||
|
||||
- `protected void WriteChannelInfo(BinaryWriter fileWriter, Test test, string testId, TickEventHandler tickEventHandler, string dataFolder, CancelRequested cancelRequested, string pathName, TestPlan testPlan)`
|
||||
Writes per-channel headers and ADC data.
|
||||
- Sorts channels by `AbsoluteDisplayOrder`, then by `ToString()`.
|
||||
- Computes homogenized time range (`dMaxStart` to `dMinEnd`) across all channels to align samples.
|
||||
- For each channel:
|
||||
- Writes channel metadata (5-char channel number, DAS channel ID, subchannel, scaling samples, pre-trigger samples, sample rate, zero level, calibration points, resolution, rack/module serials).
|
||||
- Conditionally writes `.lin` or `.dig` files for non-linear/digital channels.
|
||||
- Writes 16-bit ADC data (centered at 32767) for all samples in the homogenized range, *excluding the last 2 samples* (to match TDC RDF behavior).
|
||||
- Special handling for:
|
||||
- Squib channels (`I`/`C` suffixes).
|
||||
- Slice modules (channel numbering adjusted).
|
||||
- Digital inputs (on/off thresholding).
|
||||
- Non-linear channels (scaled via `nonLinearScaleFactor`).
|
||||
- Naturally inverted scales (e.g., SPS/SLS modules without linearization).
|
||||
|
||||
- `private double[] GetEUData(Test.Module.Channel channel)`
|
||||
Retrieves EU data for `channel` via `WriterParent.GetEUData(channel.ChannelId).Data`.
|
||||
|
||||
- `private static string GetRackSerialNumber(string serialNumber, string baseSerialNumber)`
|
||||
Returns last 4 chars of `serialNumber` or `baseSerialNumber`, left-padded to 5 chars; `"EMPTY"` if null/whitespace.
|
||||
|
||||
- `private static bool IsSlice(string sn)`
|
||||
Returns `true` if `sn` starts with `"SPS"`, `"SPT"`, `"SPD"`, `"BA"`, `"SLT"`, `"SLS"`, or `"SLD"`.
|
||||
|
||||
- `private bool HasNaturallyInvertedScaleFactor(Test.Module.Channel channel)`
|
||||
Returns `true` for SPS/SLS analog channels *without* a valid linearization formula and *not* digital.
|
||||
|
||||
- `private static int DisplayOrderComparer(object x, object y)`
|
||||
Compares two `Test.Module.Channel` instances by `AbsoluteDisplayOrder`, then by `ToString()`.
|
||||
|
||||
- `public string GetTestObjectNumber(string isocode, TestPlan plan)`
|
||||
Returns 1-based index of the `TestObject` in `plan.ISOTestObjects` matching the `TestObject` character from `isocode`.
|
||||
|
||||
- **Private Helper Methods (non-public)**
|
||||
- `CreateLinearizedData(...)`: Writes `.lin` files with EU data (ASCII CSV).
|
||||
- `CreateDigitizedData(...)`: Writes `.dig` files with EU data (ASCII CSV).
|
||||
- `CreateLinearizedDataCSV(...)`: Writes `.csv` files for debugging (ADC, mV, EU columns).
|
||||
- `Create3DIRTraccDataCSV(...)`: *Commented out*; legacy debugging utility.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **Filename constraints**
|
||||
- RDF files must end with `.001`.
|
||||
- Test name (`id`) is truncated to exactly 8 characters (via `PadRight`/`Substring` in `WriteTestInfo`).
|
||||
- `id` must contain `" RunTest"` or `" Checkout"` suffix to be accepted; otherwise, `test.Id` is used (per FB8419/36769).
|
||||
|
||||
- **Data alignment**
|
||||
- All channels are exported with a common time range (`dMaxStart` to `dMinEnd`), ensuring identical sample counts per channel.
|
||||
- The last 2 samples are *always omitted* from the final binary output (to match TDC behavior), regardless of `dataCollectionLength`.
|
||||
|
||||
- **Channel ordering**
|
||||
- Channels are sorted by `AbsoluteDisplayOrder` before serialization.
|
||||
|
||||
- **ADC centering**
|
||||
- All ADC values are written as 16-bit unsigned integers centered at `DTS.Common.Constants.ADC_MIDPOINT` (32767).
|
||||
|
||||
- **Calibration points**
|
||||
- Cal point 1 is always `+0.000E+000`.
|
||||
- Cal point 2 is `MidpointDeflection` (70% of `ADC_MIDPOINT`) scaled to EU, with special handling for digital inputs, squibs, and non-linear channels.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Dependencies *of* this module:
|
||||
- `DTS.Common.ISO.TestPlan` (for test metadata, ISO code parsing, test object numbering).
|
||||
- `DTS.Common.DAS.Concepts.DataScaler` (for scaling ADC → mV → EU).
|
||||
- `DTS.Common.Enums.Sensors.SensorConstants` (for `BridgeType` constants like `DigitalInput`, `IEPE`).
|
||||
- `DTS.Common.Utilities.Logging.APILogger` (for exception logging).
|
||||
- `DTS.Serialization.Test`, `Test.Module.Channel`, `FilteredData`, `IWriter<Test>` (serialization contracts).
|
||||
- `System.IO`, `System.Text`, `System.Globalization` (standard .NET I/O and formatting).
|
||||
|
||||
### Dependencies *on* this module:
|
||||
- Any code requiring RDF export (e.g., test export workflows, ISO compliance tools).
|
||||
- Likely consumed via `File.Exporter` to serialize `Test` instances.
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **Sample count discrepancy**:
|
||||
The last 2 samples are *always* omitted from the binary output (hardcoded in loops: `iPt <= endSample - 2`). This is intentional to match TDC RDF exports, but may cause off-by-two discrepancies with raw data downloads.
|
||||
|
||||
- **Test name normalization**:
|
||||
`id` is *only* accepted if it ends with `" RunTest"` or `" Checkout"`; otherwise, `test.Id` is used. This may cause unexpected filename changes if `id` is not properly suffixed.
|
||||
|
||||
- **Channel numbering quirks**:
|
||||
- Slice modules require manual channel offset (`+ module.Number * 3`).
|
||||
- Squib channels use `I`/`C` suffixes (current/indication) and require even/odd channel number adjustment.
|
||||
|
||||
- **Naturally inverted scales**:
|
||||
For SPS/SLS modules *without* linearization, the ADC data is inverted (`dataPoint *= -1`) *and* `ZeroMvInADC` is negated if non-zero. This is non-obvious and may cause misalignment if not handled consistently.
|
||||
|
||||
- **Digital input handling**:
|
||||
Digital channels use a threshold-based on/off conversion (5 EU per ADC step), but the logic does *not* inspect `DigitalMode` (e.g., `CCNO`, `HighToLow`)—it assumes a simple threshold. This may misrepresent edge-triggered inputs.
|
||||
|
||||
- **EU data dependency**:
|
||||
`GetEUData` relies on `_EUUnfilteredDataForLinearizedChannels` being pre-populated via `SetEUData`. If not, `KeyNotFoundException` may occur.
|
||||
|
||||
- **Unused properties**:
|
||||
`UseIsoCodeForDiadem200` and `ExtensionPrefix` are defined but not meaningfully used in the current implementation.
|
||||
|
||||
- **Legacy debugging code**:
|
||||
`Create3DIRTraccDataCSV` is commented out but retained in source—do not assume active functionality.
|
||||
|
||||
- **Error handling**:
|
||||
Exceptions during export are logged via `APILogger` *and* rethrown (or dispatched via `errorEventHandler`). This dual behavior may cause duplicate logging if handlers are registered.
|
||||
@@ -0,0 +1,299 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/SliceRaw/SliceRaw.File.IDasTimestampHeader.cs
|
||||
- Common/DTS.Common.Serialization/SliceRaw/SliceRaw.File.Reader.BadCrcException.cs
|
||||
- Common/DTS.Common.Serialization/SliceRaw/SliceRaw.File.Reader.MissingFileException.cs
|
||||
- Common/DTS.Common.Serialization/SliceRaw/SliceRaw.File.Reader.TooManyFilesException.cs
|
||||
- Common/DTS.Common.Serialization/SliceRaw/SliceRaw.File.PersistentChannel.NotInitializedException.cs
|
||||
- Common/DTS.Common.Serialization/SliceRaw/SliceRaw.File.PersistentChannel.IsInitializingException.cs
|
||||
- Common/DTS.Common.Serialization/SliceRaw/SliceRaw.File.PersistentChannel.DataTooBigForArrayException.cs
|
||||
- Common/DTS.Common.Serialization/SliceRaw/SliceRaw.File.PersistentChannel.AlreadyInitializedException.cs
|
||||
- Common/DTS.Common.Serialization/SliceRaw/SliceRaw.File.PersistentChannel.DependencyNotInitializedException.cs
|
||||
- Common/DTS.Common.Serialization/SliceRaw/SliceRaw.File.BinaryDasTimestampHeader.cs
|
||||
- Common/DTS.Common.Serialization/SliceRaw/SliceRaw.File.PersistentEuChannel.cs
|
||||
- Common/DTS.Common.Serialization/SliceRaw/SliceRaw.File.IChannelHeader.cs
|
||||
- Common/DTS.Common.Serialization/SliceRaw/ModifyChannel.cs
|
||||
- Common/DTS.Common.Serialization/SliceRaw/SliceRaw.File.BinaryChannelHeader.cs
|
||||
generated_at: "2026-04-16T03:38:20.120884+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "880f258a855611f2"
|
||||
---
|
||||
|
||||
# SliceRaw Serialization Module Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides serialization and deserialization support for binary channel data files used in the DTS SLICE data acquisition system. It defines core interfaces (`IDasTimestampHeader`, `IChannelHeader`) and concrete implementations (`BinaryDasTimestampHeader`, `BinaryChannelHeader`) for structured header metadata, along with supporting classes for reading files (`File.Reader`), managing persistent channel data (`File.PersistentChannel`), and converting raw ADC samples to engineering units (`File.PersistentEuChannel`). The module enables robust handling of binary `.chn` files containing time-series sample data, including calibration metadata, trigger information, and unit conversion parameters.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### Interfaces
|
||||
|
||||
#### `IDasTimestampHeader`
|
||||
- `uint MagicKey { get; set; }`
|
||||
Magic number identifying the binary file type.
|
||||
- `uint HeaderVersionNumber { get; set; }`
|
||||
Version number of the header format.
|
||||
- `ulong OffsetOfSampleDataStart { get; set; }`
|
||||
Byte offset from file start to the beginning of sample data.
|
||||
- `ulong NumberOfSamples { get; set; }`
|
||||
Total number of samples in the file.
|
||||
- `uint NumberOfBitsPerSample { get; set; }`
|
||||
Bit depth per sample (e.g., 16, 24, 32).
|
||||
- `uint Crc32 { get; }`
|
||||
CRC16 (despite property name) checksum of header fields.
|
||||
|
||||
#### `IChannelHeader`
|
||||
- `uint MagicKey { get; set; }`
|
||||
Magic number identifying the binary channel file type.
|
||||
- `uint HeaderVersionNumber { get; set; }`
|
||||
Version number of the channel header format.
|
||||
- `ulong OffsetOfSampleDataStart { get; set; }`
|
||||
Byte offset from file start to sample data.
|
||||
- `ulong NumberOfSamples { get; set; }`
|
||||
Total number of samples.
|
||||
- `uint NumberOfBitsPerSample { get; set; }`
|
||||
Bit depth per sample.
|
||||
- `uint AreSamplesSigned { get; set; }`
|
||||
Flag indicating if samples are signed integers.
|
||||
- `double SampleRate { get; set; }`
|
||||
Sample rate in Hz.
|
||||
- `ushort NumberOfTriggers { get; set; }`
|
||||
Number of triggers recorded.
|
||||
- `ulong[] TriggerSampleNumbers { get; set; }`
|
||||
Array of sample indices where triggers occurred.
|
||||
- `int TriggerAdjustmentSamples { get; set; }`
|
||||
Adjustment count for trigger backdating.
|
||||
- `int PreTestZeroLevelCounts { get; set; }`
|
||||
Zero-level ADC counts before testing.
|
||||
- `int RemovedADC { get; set; }`
|
||||
ADC offset removed during hardware zeroing.
|
||||
- `double Excitation { get; set; }`
|
||||
Excitation voltage applied to the channel.
|
||||
- `int ZeroMvInADC { get; set; }`
|
||||
ADC value when 0mV is injected.
|
||||
- `int WindowAverageADC { get; set; }`
|
||||
Average ADC over zero window.
|
||||
- `int OriginalOffsetADC { get; set; }`
|
||||
Initial ADC offset.
|
||||
- `int PreTestDiagnosticsLevelCounts { get; set; }`
|
||||
Diagnostics level counts before testing.
|
||||
- `double PreTestNoisePercentageOfFullScale { get; set; }`
|
||||
Pre-test noise as % of full scale.
|
||||
- `int PostTestZeroLevelCounts { get; set; }`
|
||||
Zero-level ADC counts after testing.
|
||||
- `int PostTestDiagnosticsLevelCounts { get; set; }`
|
||||
Diagnostics level counts after testing.
|
||||
- `int DataZeroLevelCounts { get; set; }`
|
||||
Zero-level ADC counts in data.
|
||||
- `double ScaleFactorMv { get; set; }`
|
||||
Scale factor in mV.
|
||||
- `double MvPerEu { get; set; }`
|
||||
Sensitivity in mV per engineering unit.
|
||||
- `ushort EuFieldLengthWithTerminator { get; set; }`
|
||||
Length of engineering unit string including null terminator.
|
||||
- `char[] EngineeringUnit { get; set; }`
|
||||
Engineering unit string (e.g., 'V', 'Pa').
|
||||
- `char[] IsoCode { get; set; }`
|
||||
ISO unit code.
|
||||
- `uint Crc32 { get; }`
|
||||
CRC16 checksum of header fields.
|
||||
|
||||
### Concrete Header Classes
|
||||
|
||||
#### `BinaryDasTimestampHeader`
|
||||
- `static uint RequiredMagicKey => 0xF15363C2`
|
||||
Required magic key for timestamp headers.
|
||||
- `static uint CurrentVersionNumber => 0x01`
|
||||
Current header version.
|
||||
- `static List<uint> KnownHeaderVersionNumbers => new List<uint>(new uint[] { 0x01 })`
|
||||
Supported header versions.
|
||||
- Implements `IDasTimestampHeader` interface.
|
||||
|
||||
#### `BinaryChannelHeader`
|
||||
- `static uint RequiredMagicKey => 0x2C36351F`
|
||||
Required magic key for channel headers.
|
||||
- `static uint CurrentVersionNumber => 0x04`
|
||||
Current header version.
|
||||
- `static List<uint> KnownHeaderVersionNumbers => new List<uint>(new uint[] { 0x01, 0x02, 0x03, 0x04 })`
|
||||
Supported header versions.
|
||||
- `uint UnpaddedEuStringPaddedEuLengthCrc32 { get; }`
|
||||
CRC16 using unpadded EU string but padded EU length field.
|
||||
- `uint UnpaddedEuCrc32 { get; }`
|
||||
CRC16 using unpadded EU string and calculated length.
|
||||
- Implements `IChannelHeader` interface.
|
||||
|
||||
### Exception Classes
|
||||
|
||||
#### `File.Reader.BadCrcException`
|
||||
- `BadCrcException()`
|
||||
Default constructor.
|
||||
- `BadCrcException(string msg)`
|
||||
Constructor with message.
|
||||
- `BadCrcException(string msg, Exception innerEx)`
|
||||
Constructor with message and inner exception.
|
||||
|
||||
#### `File.Reader.MissingFileException`
|
||||
- `MissingFileException()`
|
||||
Default constructor.
|
||||
- `MissingFileException(string msg)`
|
||||
Constructor with message.
|
||||
- `MissingFileException(string msg, Exception innerEx)`
|
||||
Constructor with message and inner exception.
|
||||
|
||||
#### `File.Reader.TooManyFilesException`
|
||||
- `TooManyFilesException()`
|
||||
Default constructor.
|
||||
- `TooManyFilesException(string msg)`
|
||||
Constructor with message.
|
||||
- `TooManyFilesException(string msg, Exception innerEx)`
|
||||
Constructor with message and inner exception.
|
||||
|
||||
#### `File.PersistentChannel.NotInitializedException`
|
||||
- `NotInitializedException()`
|
||||
Default constructor.
|
||||
- `NotInitializedException(string msg)`
|
||||
Constructor with message.
|
||||
- `NotInitializedException(string msg, Exception innerEx)`
|
||||
Constructor with message and inner exception.
|
||||
|
||||
#### `File.PersistentChannel.IsInitializingException`
|
||||
- `IsInitializingException()`
|
||||
Default constructor.
|
||||
- `IsInitializingException(string msg)`
|
||||
Constructor with message.
|
||||
- `IsInitializingException(string msg, Exception innerEx)`
|
||||
Constructor with message and inner exception.
|
||||
|
||||
#### `File.PersistentChannel.DataTooBigForArrayException`
|
||||
- `DataTooBigForArrayException()`
|
||||
Default constructor.
|
||||
- `DataTooBigForArrayException(string msg)`
|
||||
Constructor with message.
|
||||
- `DataTooBigForArrayException(string msg, Exception innerEx)`
|
||||
Constructor with message and inner exception.
|
||||
|
||||
#### `File.PersistentChannel.AlreadyInitializedException`
|
||||
- `AlreadyInitializedException()`
|
||||
Default constructor.
|
||||
- `AlreadyInitializedException(string msg)`
|
||||
Constructor with message.
|
||||
- `AlreadyInitializedException(string msg, Exception innerEx)`
|
||||
Constructor with message and inner exception.
|
||||
|
||||
#### `File.PersistentChannel.DependencyNotInitializedException`
|
||||
- `DependencyNotInitializedException()`
|
||||
Default constructor.
|
||||
- `DependencyNotInitializedException(string msg)`
|
||||
Constructor with message.
|
||||
- `DependencyNotInitializedException(string msg, Exception innerEx)`
|
||||
Constructor with message and inner exception.
|
||||
|
||||
### Other Public Types
|
||||
|
||||
#### `PersistentEuChannel`
|
||||
- `PersistentEuChannel(PersistentChannel persistentChannel, DataScaler scaler)`
|
||||
Wraps a `PersistentChannel` and converts raw samples to engineering units.
|
||||
- `PersistentChannel BasePersistentChannel { get; set; }`
|
||||
Underlying raw channel.
|
||||
- `DataScaler EuDataScaler { get; set; }`
|
||||
Converter from ADC to EU.
|
||||
- `double this[ulong i] { get; }`
|
||||
Read-only indexer returning EU value at index `i`.
|
||||
- `long Length { get; }`
|
||||
Number of samples (same as `BasePersistentChannel.Length`).
|
||||
- `void Dispose()`
|
||||
Disposes underlying channel.
|
||||
|
||||
#### `ModifyChannel` (WinForms UI)
|
||||
- `File.PersistentChannel ChannelToModify { set; }`
|
||||
Sets the channel to be modified via UI.
|
||||
- Public UI form for editing channel header metadata.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **Magic Key Validation**:
|
||||
`BinaryDasTimestampHeader` requires `MagicKey == 0xF15363C2`; `BinaryChannelHeader` requires `MagicKey == 0x2C36351F`. Headers with incorrect magic keys are invalid.
|
||||
|
||||
- **Header Versioning**:
|
||||
`BinaryDasTimestampHeader` supports only version `0x01`.
|
||||
`BinaryChannelHeader` supports versions `0x01` through `0x04`. Version-specific fields are conditionally included in CRC calculation based on `HeaderVersionNumber`.
|
||||
|
||||
- **CRC Calculation Invariants**:
|
||||
- CRC is computed over a byte array built from header fields in a specific order.
|
||||
- For `BinaryChannelHeader`, version-specific fields (`RemovedADC`, `Excitation`, `TriggerAdjustmentSamples`, etc.) are included only if `HeaderVersionNumber >=` corresponding version constant.
|
||||
- EU string padding behavior affects CRC: three CRC variants exist (`Crc32`, `UnpaddedEuCrc32`, `UnpaddedEuStringPaddedEuLengthCrc32`) with different padding rules.
|
||||
- Data arrays are padded to even byte count before CRC calculation.
|
||||
|
||||
- **PersistentChannel Initialization**:
|
||||
- Properties may only be set once (`AlreadyInitializedException` thrown on reassignment).
|
||||
- Accessing properties during initialization throws `IsInitializingException`.
|
||||
- Accessing uninitialized properties throws `NotInitializedException`.
|
||||
- Dependencies must be initialized first; otherwise `DependencyNotInitializedException` is thrown.
|
||||
|
||||
- **Array Size Limitation**:
|
||||
Attempting to load data exceeding `int.MaxValue` bytes throws `DataTooBigForArrayException`.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Internal Dependencies
|
||||
- `DTS.Common.Utilities.Logging.APILogger`
|
||||
Used for logging (commented out in CRC calculation code).
|
||||
- `DTS.Common.Utilities.Logging.Exceptional`
|
||||
Base class for header classes (indicated by `: Exceptional`).
|
||||
- `DTS.Common.DAS.Concepts.DataScaler`
|
||||
Used by `PersistentEuChannel` for unit conversion.
|
||||
- `DTS.Common.Utils.Utils.Math_DoCRC16Step`
|
||||
CRC calculation helper (despite property name, CRC16 is used, not CRC32).
|
||||
|
||||
### External Dependencies
|
||||
- `System` (Core .NET types)
|
||||
- `System.Collections.Generic`
|
||||
- `System.Text`
|
||||
- `System.Windows.Forms` (for `ModifyChannel` UI form)
|
||||
- `DTS.Common.DAS.Concepts` (for `DataScaler`)
|
||||
- `DTS.Common.Utilities.DotNetProgrammingConstructs` (for `Property<T>` wrapper)
|
||||
|
||||
### Inferred Usage
|
||||
- `File.Reader` class (not shown in source but referenced in exception files) likely handles file I/O and header parsing.
|
||||
- `File.PersistentChannel` (not shown) likely implements `IChannelHeader` and manages raw sample data.
|
||||
- `ModifyChannel` form suggests integration with desktop UI for header editing.
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **CRC Name Mismatch**:
|
||||
Properties named `Crc32` actually compute CRC16 (16-bit), not CRC32. This is evident from `Math_DoCRC16Step` usage and `ushort crc` variable.
|
||||
|
||||
- **EU String Padding Ambiguity**:
|
||||
CRC calculation has three variants with different EU string padding rules:
|
||||
- `Crc32`: Uses original EU string (with padding if odd length).
|
||||
- `UnpaddedEuCrc32`: Strips leading/trailing whitespace before padding.
|
||||
- `UnpaddedEuStringPaddedEuLengthCrc32`: Strips padding but uses original `EuFieldLengthWithTerminator` value (including potential +1 bug).
|
||||
|
||||
- **Header Version Field Inclusion**:
|
||||
CRC calculation conditionally includes fields based on `HeaderVersionNumber`. For example:
|
||||
- `RemovedADC` included only if `HeaderVersionNumber >= 2`
|
||||
- `Excitation`, `TriggerAdjustmentSamples`, etc., included only if `HeaderVersionNumber >= 3`
|
||||
- `WindowAverageADC` included only if `HeaderVersionNumber >= 4`
|
||||
|
||||
- **`EuFieldLengthWithTerminator` Bug Tolerance**:
|
||||
CRC calculation accommodates a known bug where `EuFieldLengthWithTerminator` is stored as `actual_length + 1`. Logic checks if `EuFieldLengthWithTerminator > EngineeringUnit.Length + 1` to detect this.
|
||||
|
||||
- **`TriggerSampleNumbers` Array Handling**:
|
||||
`ModifyChannel` UI only edits the first trigger sample (`TriggerSampleNumbers[0]`), ignoring additional triggers.
|
||||
|
||||
- **Read-Only `PersistentEuChannel` Indexer**:
|
||||
Setting values via `PersistentEuChannel[i] = value` throws `NotSupportedException`, even though the indexer has a setter.
|
||||
|
||||
- **Partial Class Structure**:
|
||||
Classes like `File`, `Reader`, and `PersistentChannel` are declared as `partial`, implying implementation is split across multiple files not included in this documentation set. Behavior of `File.Reader` and `File.PersistentChannel` cannot be fully inferred.
|
||||
|
||||
- **Missing File Exception Handling**:
|
||||
`MissingFileException` is thrown when a file is not found, but exact conditions (e.g., during `File.Reader` construction) are not visible in source.
|
||||
|
||||
- **No Public Constructor Visibility**:
|
||||
Constructors for `File.Reader` and `File.PersistentChannel` are not shown, making initialization patterns unclear.
|
||||
|
||||
- **No Documentation for `StampCrc()`**:
|
||||
`ModifyChannel.btnWrite_Click` calls `_channel.StampCrc()`, but this method is not defined in the provided source.
|
||||
@@ -0,0 +1,132 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/SoMat/SoMat.File.cs
|
||||
- Common/DTS.Common.Serialization/SoMat/SoMatTestHeader.cs
|
||||
- Common/DTS.Common.Serialization/SoMat/SoMatChannel.cs
|
||||
- Common/DTS.Common.Serialization/SoMat/SoMat.File.Writer.cs
|
||||
generated_at: "2026-04-16T03:38:52.973808+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "75e43dc7ec17e504"
|
||||
---
|
||||
|
||||
# SoMat
|
||||
|
||||
## SoMat Serialization Module Documentation
|
||||
|
||||
---
|
||||
|
||||
### 1. Purpose
|
||||
|
||||
This module implements serialization of `Test` objects (from `DTS.Serialization.Test`) into a proprietary text-based format compatible with Diadem (a data analysis and reporting tool from National Instruments). It generates a single `.txt` file containing structured metadata (test header, channel definitions) followed by tab-delimited numeric data arrays. The module is part of the `DTS.Serialization.SoMat` namespace and serves as a concrete implementation of a file writer for SoMat-formatted output, primarily used for exporting test data for post-processing or reporting.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
#### `DTS.Serialization.SoMat.File`
|
||||
|
||||
- **`File()`**
|
||||
Parameterless constructor. Initializes the base `Serialization.File` with the string `"SoMat"` as the format name.
|
||||
|
||||
- **`static string Extension`**
|
||||
Returns the file extension for SoMat files: `".txt"`.
|
||||
|
||||
- **`IWriter<Test> Exporter`**
|
||||
Lazily-initialized property that returns an `IWriter<Test>` instance (`SoMat.File.Writer`) using `DefaultEncoding`. Throws an `Exception` with inner exception if writer instantiation fails.
|
||||
|
||||
#### `DTS.Serialization.SoMat.File.Writer`
|
||||
|
||||
- **`internal Writer(File fileType, int encoding)`**
|
||||
Internal constructor; initializes the base `Writer<File>` with the provided `fileType` and `encoding`.
|
||||
|
||||
- **`void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)`**
|
||||
**Throws `NotSupportedException`** — this overload is explicitly unsupported.
|
||||
|
||||
- **`void Write(string pathname, string id, string dataFolder, Test test, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Test.Module.Channel tmChannel, int channelNumber, BeginEventHandler beginEventHandler, CancelEventHandler cancelEventHandler, EndEventHandler endEventHandler, TickEventHandler tickEventHandler, ErrorEventHandler errorEventHandler, CancelRequested cancelRequested, double minStartTime, int dataCollectionLength)`**
|
||||
Writes a SoMat file to `pathname`.
|
||||
- Constructs a `SoMatTestHeader` using `test` and `FilteredData[]` (from `FilteredData` property).
|
||||
- Serializes header and channel metadata to the file.
|
||||
- Writes `"DM_Start=\r\n"` as a data section marker.
|
||||
- Iterates over sample indices up to `maxSamples` (max across all modules), writing one row per sample with tab-separated values (formatted as `"0.00000E+00"`), one column per channel.
|
||||
- Invokes event handlers (`beginEventHandler`, `tickEventHandler`, `endEventHandler`, `errorEventHandler`) for progress and error reporting.
|
||||
- Logs exceptions via `APILogger.Log`.
|
||||
- Throws exceptions if no `errorEventHandler` is provided.
|
||||
|
||||
- **`FilteredData[] FilteredData`**
|
||||
Property to set/get the `FilteredData[]` array used during serialization. Required before calling the multi-parameter `Write` method.
|
||||
|
||||
#### `DTS.Serialization.SoMat.SoMatTestHeader`
|
||||
|
||||
- **`SoMatTestHeader(Test test, FilteredData[] filteredData)`**
|
||||
Constructor that populates header fields from `test` and `filteredData`.
|
||||
- `TestTitle` ← `test.Id`
|
||||
- `RunDateTime` ← formatted `test.InceptionDate`
|
||||
- `Operator` ← current Windows user name (falls back to empty string on failure)
|
||||
- `NumLogChannels` ← `test.Channels.Count` (capped by `filteredData.Length`)
|
||||
- `NumDataModes` ← `1` (hardcoded)
|
||||
- Populates `_channels` list by constructing `SoMatChannel` objects.
|
||||
|
||||
- **`void Serialize(StreamWriter sw)`**
|
||||
Writes header fields in `DM_`-prefixed key=value format to `sw`, followed by a blank line.
|
||||
|
||||
#### `DTS.Serialization.SoMat.SoMatChannel`
|
||||
|
||||
- **`SoMatChannel(Test.Module.Channel channel, int logicalChannel, FilteredData filteredData, int moduleArrayIndex, int numChannelsPerModule, DateTime inceptionDateTime)`**
|
||||
Constructor that initializes channel metadata from `channel`, `filteredData`, and test context.
|
||||
- `LogicalChannel` ← `logicalChannel`
|
||||
- `ChanName` ← `channel.ChannelDescriptionString` (via `AnalogInputChannel`)
|
||||
- `NumDataPoints` ← `channel.ParentModule.NumberOfSamples`
|
||||
- `SampleRate`, `TimeBase`, `MaxValue`, `MinValue`, `UserMax`, `UserMin`, `ElapsedTime`, `AcquisitionRate`, `RTCStart`, `RTCEnd`, `PhysicalChannelNumber` computed from module/channel/test data.
|
||||
- `AxisUnitsDim2` ← `engineeringUnits.TrimEnd()`
|
||||
- `AxisLabelDim2`, `DescDim2` ← `channel.SerialNumber`
|
||||
|
||||
- **`void Serialize(StreamWriter sw)`**
|
||||
Writes channel metadata in `DM_`-prefixed key=value format (plus legacy `2100_` and `HDWParams`/`CALParams`/`DGParams` keys) to `sw`, followed by a blank line.
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
|
||||
- **File extension**: All output files use `.txt`.
|
||||
- **Data format**: Data section begins with `"DM_Start=\r\n"` and consists of rows of tab-separated floating-point values in scientific notation (`"0.00000E+00"`).
|
||||
- **Channel ordering**: Channels are serialized in the order of `test.Channels`, with index `i` mapped to `filteredData[i]`.
|
||||
- **Physical channel numbering**: `PhysicalChannelNumber = 1 + moduleArrayIndex * numChannelsPerModule + aic.Number`, where `numChannelsPerModule = 3` (hardcoded in `SoMatChannel` constructor).
|
||||
- **Header consistency**: `NumLogChannels` in `SoMatTestHeader` matches the number of `SoMatChannel` objects serialized.
|
||||
- **Time base**: If `TimeOfFirstSampleValid` is false, `TimeBase` is computed as `(StartRecordSampleNumber - TriggerSampleNumbers[0]) / SampleRateHz`.
|
||||
- **Data mode**: `NumDataModes` is always `1`; `DataModeType` is always `"TIMHIS"`.
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
|
||||
#### Internal Dependencies (from source):
|
||||
- `DTS.Serialization.Test` (namespace `DTS.Serialization`) — core test model.
|
||||
- `DTS.Serialization.SoMat.FilteredData` — assumed to be a type with a `double[] Data` property (used in `SoMatChannel` and `Writer.Write`).
|
||||
- `DTS.Serialization.SoMat.Test.Module.Channel`, `Test.Module.AnalogInputChannel`, `Test.Module` — test model subtypes.
|
||||
- `DTS.Common.Utilities.Logging.APILogger` — for logging exceptions.
|
||||
- `System.IO.StreamWriter`, `System.Text.Encoding`, `System.Security.Principal.WindowsIdentity`, `System.Linq`, `System.Windows.Forms.Application` (for `DoEvents()`).
|
||||
|
||||
#### External Dependencies:
|
||||
- **Diadem compatibility**: Output format is designed for consumption by Diadem (per `Writer` summary).
|
||||
- **Windows-specific**: Uses `WindowsIdentity.GetCurrent()` for operator name.
|
||||
|
||||
#### Dependencies on this module:
|
||||
- `DTS.Serialization.Test` consumers (e.g., test export pipelines) likely depend on `SoMat.File.Exporter` to generate `.txt` files.
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
|
||||
- **Unsupported `Write` overload**: The 7-parameter `Write` method throws `NotSupportedException`. Only the 17-parameter overload is functional.
|
||||
- **Hardcoded `numChannelsPerModule = 3`**: In `SoMatChannel` constructor, `numChannelsPerModule` is passed as `3`. This may be incorrect if modules have varying channel counts.
|
||||
- **`FilteredData` must be set manually**: The `Writer.FilteredData` property must be assigned before calling `Write`; otherwise, `FilteredData` is `null`, causing a `NullReferenceException` during header construction.
|
||||
- **`TimeBase` fallback logic**: When `TimeOfFirstSampleValid` is false, `TriggerSampleNumbers[0]` is used. If `TriggerSampleNumbers` is empty or `StartRecordSampleNumber` is invalid, this may produce incorrect or NaN values.
|
||||
- **Encoding**: Uses `Encoding.Default` (ANSI code page) for file writing — may cause issues with non-ASCII characters.
|
||||
- **Event handler requirements**: If `errorEventHandler` is `null` and an exception occurs, the exception is rethrown. Otherwise, it is suppressed and only passed to `errorEventHandler`.
|
||||
- **`DM_Start` marker**: The `"DM_Start=\r\n"` line is written *before* data rows, but no corresponding `"DM_Stop"` or end marker is present.
|
||||
- **`NumDataModes` hardcoded**: Always `1`, regardless of actual data modes in the test.
|
||||
- **`PhysicalChannelNumber` assumes fixed `numChannelsPerModule`**: Calculation may be incorrect if `numChannelsPerModule` differs from 3 in practice.
|
||||
- **No validation of `filteredData.Length` vs `test.Channels.Count`**: The `SoMatTestHeader` constructor silently truncates to the smaller of the two counts.
|
||||
|
||||
None identified beyond these.
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/StringResources/Strings.Designer.cs
|
||||
generated_at: "2026-04-16T03:35:11.595003+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "0432c06ee66319f4"
|
||||
---
|
||||
|
||||
# StringResources
|
||||
|
||||
## Documentation Page: `DTS.Serialization.StringResources.Strings`
|
||||
|
||||
---
|
||||
|
||||
### 1. **Purpose**
|
||||
|
||||
This module provides a strongly-typed, auto-generated resource class (`Strings`) for accessing localized string resources used throughout the DTS serialization subsystem—specifically in error and diagnostic messaging related to slice control logic, event handling, DAS (Data Acquisition System) list validation, and equality comparisons. It serves as a centralized, compile-time-safe abstraction layer over the underlying `ResourceManager`, enabling developers to retrieve localized messages by strongly-typed property access rather than string keys. The class is not intended for direct business logic use but for consistent, localized error reporting in higher-level components (e.g., validation, comparison, or construction failures).
|
||||
|
||||
---
|
||||
|
||||
### 2. **Public Interface**
|
||||
|
||||
All members are `internal` (not `public`), meaning they are only accessible within the same assembly (`DTS.Serialization.StringResources`). No types or methods are exposed to external consumers.
|
||||
|
||||
#### Class: `Strings`
|
||||
- **Namespace**: `DTS.Serialization.StringResources`
|
||||
- **Attributes**: `[GeneratedCode]`, `[DebuggerNonUserCode]`, `[CompilerGenerated]`
|
||||
- **Constructor**:
|
||||
`internal Strings()`
|
||||
Private parameterless constructor; prevents external instantiation.
|
||||
|
||||
- **Static Properties** (read-only accessors to localized strings):
|
||||
- `internal static ResourceManager ResourceManager { get; }`
|
||||
Returns a cached `ResourceManager` instance for the resource file `"DTS.Serialization.StringResources.Strings"`. Lazily initializes on first access.
|
||||
|
||||
- `internal static CultureInfo Culture { get; set; }`
|
||||
Gets or sets the UI culture used for resource lookups. Overrides the current thread’s `CurrentUICulture` for all lookups via this class.
|
||||
|
||||
- **String Properties** (each returns a localized string for a specific message key):
|
||||
- `internal static string DTS_Slice_Control_Equals_ComparisonFailedString { get; }`
|
||||
- `internal static string DTS_Slice_Control_Event_ConstructionFailedString { get; }`
|
||||
- `internal static string DTS_Slice_Control_Event_Event_DASTestIdMismatchString { get; }`
|
||||
- `internal static string DTS_Slice_Control_Event_Event_EmptyDasListString { get; }`
|
||||
- `internal static string DTS_Slice_Control_Event_Event_FailedToDetermineIdOrDescriptionFromConfigurationString { get; }`
|
||||
- `internal static string DTS_Slice_Control_Event_Event_NullDasListString { get; }`
|
||||
- `internal static string DTS_Slice_Control_Event_Module_Channel_DataEquals_ComparisonFailedString { get; }`
|
||||
- `internal static string DTS_Slice_Control_Event_Module_ChannelsEquals_ComparisonFailedString { get; }`
|
||||
- `internal static string DTS_Slice_Control_Event_Module_TriggerSampleNumbersEquals_ComparisonFailedString { get; }`
|
||||
- `internal static string DTS_Slice_Control_Event_ModuleEquals_ComparisonFailedString { get; }`
|
||||
- `internal static string DTS_Slice_Control_NullIndicatorString { get; }`
|
||||
|
||||
Each property internally calls `ResourceManager.GetString(key, resourceCulture)`.
|
||||
|
||||
---
|
||||
|
||||
### 3. **Invariants**
|
||||
|
||||
- The class is **thread-safe for read-only access** to `ResourceManager` and `Culture` due to the null-check-and-assign pattern in `ResourceManager` (though not explicitly guarded with locks—relies on .NET’s thread-safe initialization of static fields).
|
||||
- `resourceCulture` is `null` by default; if set, it overrides the thread’s `CurrentUICulture` for all subsequent lookups.
|
||||
- All string keys are **hardcoded in the property getters** and must match keys in the corresponding `.resx` file (e.g., `DTS_Slice_Control_Equals_ComparisonFailedString`). Mismatches would cause runtime `MissingManifestResourceException` or `NullReferenceException` (if `GetString` returns `null`).
|
||||
- The class is **immutable at runtime**—no mutable state beyond the static `resourceMan` and `resourceCulture` fields.
|
||||
|
||||
---
|
||||
|
||||
### 4. **Dependencies**
|
||||
|
||||
- **Depends on**:
|
||||
- `System.Resources.ResourceManager`
|
||||
- `System.Globalization.CultureInfo`
|
||||
- The compiled satellite or main assembly containing the corresponding `.resx` file (expected to be embedded as `DTS.Serialization.StringResources.Strings.resources`).
|
||||
- `System.CodeDom.Compiler`, `System.Diagnostics`, `System.Runtime.CompilerServices`, `System.ComponentModel` (via attributes).
|
||||
|
||||
- **Used by**:
|
||||
- Other components in the `DTS.Serialization` namespace (e.g., comparison logic, event construction/validation code) that need to throw or log localized messages using the above keys.
|
||||
*(Exact consumers are not visible in this file alone, but naming conventions strongly suggest usage in slice control, event, module, channel, and DAS list validation code.)*
|
||||
|
||||
---
|
||||
|
||||
### 5. **Gotchas**
|
||||
|
||||
- **Auto-generated**: This file is regenerated automatically (e.g., via ResGen or Visual Studio build). **Manual edits will be overwritten**. Changes must be made in the source `.resx` file.
|
||||
- **No null-safety guarantee**: `ResourceManager.GetString(...)` may return `null` if a key is missing from the `.resx` file (e.g., due to a mismatch between key name and resource file). This could lead to `NullReferenceException` if callers assume non-null return.
|
||||
- **No documentation of actual string values**: The XML comments only show *sample* text (e.g., `"DTS_Slice_Control_Equals_ComparisonFailedString"`), not the real localized content. The actual messages are defined in the `.resx` file (not provided here).
|
||||
- **No public API surface**: This is an internal helper—consumers must be in the same assembly. External callers cannot reference it directly.
|
||||
- **Culture override behavior**: Setting `Strings.Culture` affects *all* subsequent lookups in the AppDomain, which may cause unintended side effects in multi-threaded scenarios if not coordinated.
|
||||
|
||||
None identified beyond the above.
|
||||
@@ -0,0 +1,175 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/TDAS/TDAS.File.Reader.BadCrcException.cs
|
||||
- Common/DTS.Common.Serialization/TDAS/TDAS.File.Reader.MissingFileException.cs
|
||||
- Common/DTS.Common.Serialization/TDAS/TDAS.File.Reader.TooManyFilesException.cs
|
||||
- Common/DTS.Common.Serialization/TDAS/TDAS.File.IChannelHeader.cs
|
||||
- Common/DTS.Common.Serialization/TDAS/TDAS.File.PersistentChannel.NotInitializedException.cs
|
||||
- Common/DTS.Common.Serialization/TDAS/TDAS.File.PersistentChannel.DataTooBigForArrayException.cs
|
||||
- Common/DTS.Common.Serialization/TDAS/TDAS.File.cs
|
||||
- Common/DTS.Common.Serialization/TDAS/TDAS.File.BinaryChannelHeader.cs
|
||||
- Common/DTS.Common.Serialization/TDAS/TDAS.File.Writer.cs
|
||||
- Common/DTS.Common.Serialization/TDAS/TLFBin.cs
|
||||
generated_at: "2026-04-16T03:38:54.525487+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "8202fee238e4de73"
|
||||
---
|
||||
|
||||
# TDAS Serialization Module Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides serialization and deserialization support for TDAS (Test Data Acquisition System) files, specifically handling `.tlf` (text-based metadata) and `.BIN` (binary channel data) file formats used by Diversified Technical Systems, Inc. It defines core types—including `File`, `Writer`, `Reader`, `PersistentChannel`, and supporting classes like `TDASBinaryChannelHeader`—to manage test metadata, channel headers, and raw data. The module enables structured export/import of test data with support for channel-specific metadata (e.g., acquisition rate, calibration levels, signal-to-noise ratio), CRC validation, and exception handling for common file-level and data-level errors.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### Exception Types
|
||||
|
||||
All exception types are nested within `File` or `File.PersistentChannel` and extend `Exception` or `ApplicationException`. Each provides three constructors: parameterless, `string msg`, and `string msg, Exception innerEx`.
|
||||
|
||||
- **`File.Reader.BadCrcException`**
|
||||
Thrown when a CRC validation failure occurs during file reading (e.g., corrupted binary channel data or header).
|
||||
|
||||
- **`File.Reader.MissingFileException`**
|
||||
Thrown when an expected file (e.g., `.tlf` or `.BIN`) is not found during deserialization.
|
||||
|
||||
- **`File.Reader.TooManyFilesException`**
|
||||
Thrown when the number of channel files exceeds an internal limit during deserialization.
|
||||
|
||||
- **`File.PersistentChannel.NotInitializedException`**
|
||||
Thrown when attempting to access a property of `PersistentChannel` that has not yet been initialized (e.g., reading `Data` before it's loaded).
|
||||
|
||||
- **`File.PersistentChannel.DataTooBigForArrayException`**
|
||||
Thrown when attempting to materialize a large dataset into an array that exceeds safe memory constraints.
|
||||
|
||||
### Core Types
|
||||
|
||||
- **`File`**
|
||||
Main entry point for TDAS file operations. Extends `Serialization.File` and implements `IWritable<Test>`.
|
||||
- **`static string Extension => ".tlf"`**
|
||||
The file extension for the primary metadata file.
|
||||
- **`static string TestFileExtension => ".tlf"`**
|
||||
Alias for `Extension`; used for test metadata files.
|
||||
- **`static string ChannelFileExtension => ".BIN"`**
|
||||
File extension for binary channel data files.
|
||||
- **`static string CalculatedChannelFileExtension => ".cchn"`**
|
||||
File extension for calculated channel files.
|
||||
- **`IWriter<Test> Exporter`**
|
||||
Lazily-initialized writer instance for serializing `Test` objects.
|
||||
- **`IReader<Test> Importer`**
|
||||
Lazily-initialized reader instance for deserializing `Test` objects.
|
||||
- **`int GetChannelNumberFromChannelFileName(string channelFileName)`**
|
||||
Extracts the 3-digit channel number from a channel filename (e.g., `"test.tlf001.BIN"` → `1`). Throws if parsing fails.
|
||||
|
||||
- **`File.TDASBinaryChannelHeader`**
|
||||
Implements `IChannelHeader` and encapsulates binary channel header fields. Used to serialize/deserialize header metadata and compute CRCs.
|
||||
- **Properties (get/set):**
|
||||
`AcquisitionRate`, `NumberOfPreT0DataPoints`, `NumberOfPostT0DataPoints`,
|
||||
`PreZeroLevelInCnts`, `PreCalLevelInCnts`, `SignalToNoiseRatioInDb`,
|
||||
`PostZeroLevelInCnts`, `PostCalLevelInCnts`, `DataZeroLevelInCnts`,
|
||||
`ScaleFactorMVPerCnt`, `ScaleFactorEUPerCnt`.
|
||||
- **`UInt32 Crc32 { get; }`**
|
||||
Computes CRC32 over all header fields (no EU string padding stripping).
|
||||
- **`UInt32 UnpaddedEuCrc32 { get; }`**
|
||||
Computes CRC32 with EU string padding stripped.
|
||||
- **`UInt32 UnpaddedEuStringPaddedEuLengthCrc32 { get; }`**
|
||||
Computes CRC32 with EU string stripped but EU length field included.
|
||||
- **`private UInt32 CalculateCrc32(bool stripEuPadding, bool bKeepEuLength)`**
|
||||
Internal CRC calculation using `Utils.Math_DoCRC16Step` on 16-bit word pairs of header data.
|
||||
|
||||
- **`File.Writer`**
|
||||
Internal class implementing `IWriter<Test>` for writing `Test` objects to disk.
|
||||
- **`void Write(string pathname, string id, string dataFolder, Test test, ...)`**
|
||||
Writes a `Test` to disk:
|
||||
- Serializes metadata to `<pathname>.tlf` using `TLF` class.
|
||||
- Creates backup copy of `.tlf` file.
|
||||
- Writes binary channel data to `<pathname>.NNN.BIN` files (`.BIN` extension), where `NNN` is a 3-digit channel number.
|
||||
- Supports event callbacks (`beginEventHandler`, `tickEventHandler`, `errorEventHandler`, etc.).
|
||||
- Throws `NotSupportedException` for the 5-parameter overload.
|
||||
- **`void Initialize(...)`**
|
||||
Currently a no-op stub.
|
||||
|
||||
- **`IChannelHeader`**
|
||||
Interface defining contract for channel header metadata (implemented by `TDASBinaryChannelHeader`).
|
||||
All properties are get/set; see `TDASBinaryChannelHeader` for descriptions.
|
||||
|
||||
- **`TLFBin`**
|
||||
Helper class for serializing binary channel data with resampling and scaling.
|
||||
- **Properties (get/set):**
|
||||
`AcquisitionRate`, `PreTriggerDataPoints`, `PostTriggerDataPoints`,
|
||||
`PreZeroLevel`, `PreCalLevel`, `SignalToNoiseRatio`,
|
||||
`PostZeroLevel`, `PostCalLevel`, `SuperSampleRate`.
|
||||
- **`TLFBin(Test.Module.Channel channel, double superSampleRate)`**
|
||||
Constructor computes header fields and scaling parameters from `channel` and `superSampleRate`.
|
||||
- `PreCalLevel` is hardcoded to `0.7 * short.MaxValue` (10922).
|
||||
- `SignalToNoiseRatio` computed from `NoiseAsPercentageOfFullScale` and full-scale ADC range.
|
||||
- `PostZeroLevel` and `PostCalLevel` are currently unimplemented (set to `0`).
|
||||
- **`void Serialize(BinaryWriter bw, Test.Module.Channel channel)`**
|
||||
Writes binary data to `BinaryWriter`:
|
||||
- Writes header (11 fields: `SuperSampleRate`, `PreTriggerDataPoints`, ..., `ScaleFactorEUPerCnt`).
|
||||
- Writes resampled ADC values (16-bit signed) for each sample, with interpolation.
|
||||
- For digital inputs (`Bridge == DigitalInput`), writes 16-bit digital values based on `DigitalMode` and `DigitalMultiplier`.
|
||||
- For linearized sensors, constrains `newADC` to `short.MinValue`/`short.MaxValue` to avoid underflow.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **File Naming Convention:**
|
||||
Channel binary files follow `<base>.NNN.BIN`, where `NNN` is a 3-digit channel number (e.g., `001`, `002`, `901` for squib channels). Channel numbers are extracted via `GetChannelNumberFromChannelFileName`, which assumes the last 3 characters before `.BIN` are digits.
|
||||
|
||||
- **CRC Computation:**
|
||||
CRC32 is computed over 16-bit words (little-endian) of header data. Padding is added if data length is odd. Uses `Utils.Math_DoCRC16Step` (not standard CRC32), and the result is returned as `UInt32`.
|
||||
|
||||
- **Data Resampling:**
|
||||
`TLFBin.Serialize` resamples data to `SuperSampleRate` using linear interpolation. The resampling factor `rate = ceil(SuperSampleRate / AcquisitionRate)` is applied per sample.
|
||||
|
||||
- **Digital Input Handling:**
|
||||
Digital channels output 16-bit values based on `DigitalMode` (e.g., `CCNC`, `TLH`) and thresholds (`breakPoint`). Values are determined per interpolated step.
|
||||
|
||||
- **Linearization Constraints:**
|
||||
For linearized sensors, `newADC` is clamped to `short.MinValue`/`short.MaxValue` to prevent overflow/underflow during serialization (see `TLFBin.Serialize`).
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
- **Internal Dependencies:**
|
||||
- `DTS.Common.Utilities.DotNetProgrammingConstructs.Property<T>` (used in `File` for static extension properties).
|
||||
- `DTS.Common.Utilities.Logging.APILogger` (used in `File.Writer.Write` for error logging).
|
||||
- `DTS.Common.Constant` and `DTS.Common.Enums.Sensors.SensorConstants` (used in `TLFBin` constructor for `BridgeType.DigitalInput`).
|
||||
- `DTS.Common.Enums.DigitalInputModes` (used in `TLFBin.Serialize` for digital input mode handling).
|
||||
- `SliceRaw.File.Reader.GetDataScaler` (used in `TLFBin.Serialize` to obtain scaling parameters).
|
||||
- `Utils.Math_DoCRC16Step` (used in `TDASBinaryChannelHeader.CalculateCrc32`).
|
||||
- `Serialization.File`, `IWriter<Test>`, `IReader<Test>` (base types for `File`, `Writer`, and `Reader`).
|
||||
|
||||
- **External Dependencies:**
|
||||
- `System`, `System.IO`, `System.Linq`, `System.Text`, `System.Collections.Generic` (standard .NET libraries).
|
||||
- `DTS.Serialization.Test` and its nested types (`Test.Module.Channel`, `Test.Module.AnalogInputChannel`, `Test.Module.Channel.PersistentChannelInfo`).
|
||||
- `FilteredData`, `BeginEventHandler`, `CancelEventHandler`, etc. (event delegates for progress/error callbacks).
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **`TDASBinaryChannelHeader.CalculateCrc32` uses CRC16, not CRC32:**
|
||||
Despite the property names (`Crc32`, `UnpaddedEuCrc32`, etc.), the implementation computes a 16-bit CRC using `Math_DoCRC16Step` and returns it as `UInt32`. This is likely a historical naming inconsistency.
|
||||
|
||||
- **`PreCalLevel` is hardcoded:**
|
||||
In `TLFBin` constructor, `PreCalLevel` is set to `0.7 * short.MaxValue` (10922) instead of a configurable value. The comment suggests this is a placeholder.
|
||||
|
||||
- **`PostZeroLevel` and `PostCalLevel` are unimplemented:**
|
||||
Both are set to `0` in `TLFBin` constructor with `@TODO` comments indicating missing data sources.
|
||||
|
||||
- **Digital input `breakPoint` logic is complex and mode-dependent:**
|
||||
Thresholds differ by `DigitalMode` (e.g., `CCNC` vs `TLH`) and input type (current vs voltage). Misconfiguration may lead to incorrect digital output values.
|
||||
|
||||
- **`TLFBin.Serialize` may produce out-of-range values for linearized sensors:**
|
||||
Although `newADC` is clamped to `short.MinValue`/`short.MaxValue`, the comment notes this was added to fix underflow in bug #14496. Ensure scaling factors and sensor capacities are valid to avoid unexpected clamping.
|
||||
|
||||
- **Channel number extraction is fragile:**
|
||||
`GetChannelNumberFromChannelFileName` assumes filenames end with `.BIN` or `.bin` and that the 3 characters before the extension are digits. Filenames like `_C001.BIN` are handled, but edge cases (e.g., `.BIN` in middle of name) may cause errors.
|
||||
|
||||
- **`File.Writer.Write` has two overloads, only one implemented:**
|
||||
The 5-parameter overload throws `NotSupportedException`. Ensure callers use the 15-parameter version.
|
||||
|
||||
- **No public `Reader` class defined in source:**
|
||||
While `File.Importer` returns `IReader<Test>`, the `Reader` class is not defined in the provided files. Its implementation is likely in `TDAS.File.Reader.cs` (referenced in comments but not included).
|
||||
|
||||
- **Encoding assumptions:**
|
||||
`File.Writer.Write` uses `Encoding.Default` for `.tlf` serialization. This may cause portability issues across systems with different default encodings.
|
||||
118
enriched-qwen3-coder-next/Common/DTS.Common.Serialization/TDM.md
Normal file
118
enriched-qwen3-coder-next/Common/DTS.Common.Serialization/TDM.md
Normal file
@@ -0,0 +1,118 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/TDM/File.cs
|
||||
- Common/DTS.Common.Serialization/TDM/TDMParameterDlg.cs
|
||||
- Common/DTS.Common.Serialization/TDM/Writer.cs
|
||||
- Common/DTS.Common.Serialization/TDM/TestHeader.cs
|
||||
- Common/DTS.Common.Serialization/TDM/TDMParameterDlg.Designer.cs
|
||||
- Common/DTS.Common.Serialization/TDM/ChannelHeader.cs
|
||||
generated_at: "2026-04-16T03:39:24.855976+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "3ac6639dcd230dd5"
|
||||
---
|
||||
|
||||
# TDM Serialization Module Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides serialization support for exporting test data to the TDM (Test Data Manager) CSV format, specifically targeting the CFC1000 specification. It enables conversion of internal `Test` objects into structured CSV files containing test metadata, channel headers, and sampled data, with support for time-range filtering (start/stop), subsampling, and optional filtering. The module exists to interface with external tools or systems (e.g., TTS, TEMA, TDAS) that consume TDM-formatted data, ensuring compatibility through precise adherence to the expected file structure and field semantics.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### `DTS.Serialization.TDM.File`
|
||||
- **`File()`**
|
||||
Constructor. Initializes the file type with the fixed format name `"TDM CFC1000"` (passed to `base("TDM CFC1000")`).
|
||||
- **`Exporter` (property, `IWriter<Test>`)**
|
||||
Returns a lazily-initialized `Writer` instance configured with this `File` instance and `DefaultEncoding`. Sets the `Start` and `Stop` properties on the writer before returning.
|
||||
- **`Start` (property, `double`)**
|
||||
Gets/sets the start time (in seconds) for export filtering.
|
||||
- **`Stop` (property, `double`)**
|
||||
Gets/sets the stop time (in seconds) for export filtering.
|
||||
|
||||
### `DTS.Serialization.TDM.Writer`
|
||||
- **`Writer(File fileType, int encoding)`** *(internal constructor)*
|
||||
Initializes the writer with the specified `File` type and encoding.
|
||||
- **`AllowTTSExportFiltering` (property, `bool`, default `false`)**
|
||||
Controls whether filtered data export is enabled.
|
||||
- **`Start`, `Stop` (properties, `double`)**
|
||||
Get/set the time range (in seconds) to export. Rounded to 3 decimal places internally during `Write`.
|
||||
- **`FilteredData` (property, `List<FilteredData>`)**
|
||||
Holds precomputed filtered data (used when `AllowTTSExportFiltering` is `true`).
|
||||
- **`Test` (property, `Test`)**
|
||||
The test object being exported.
|
||||
- **`IncrementLevel` (property, `ulong`, read-only)**
|
||||
Controls granularity of progress updates during export (set dynamically based on estimated sample count).
|
||||
- **`SubSampleInterval` (property, `ushort`)**
|
||||
Subsampling factor applied during export.
|
||||
- **`ExtensionPrefix` (property, `string`, default `""`)**
|
||||
Optional string appended to the output filename before `.csv`.
|
||||
- **`Write(string pathname, string id, string dataFolder, Test target, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Test.Module.Channel tmChannel, int channelNumber, BeginEventHandler, CancelEventHandler, EndEventHandler, TickEventHandler, ErrorEventHandler, CancelRequested, double minStartTime, int dataCollectionLength)`**
|
||||
Primary export method. Serializes the `Test` to a CSV file at `pathname`. Performs rounding of `Start`/`Stop` to 3 decimal places, computes progress increments, and invokes `DoExport`. Notable: `pathname` is used as a directory; the actual file path is `Path.Combine(pathname, Test.Id)` with optional suffixes.
|
||||
- **`DoExport(bool bFiltered, string pathname, double start, double stop, bool allowTTSFilteredExport)`** *(private)*
|
||||
Core export logic: constructs the output filename, opens a `StreamWriter` with UTF-8 encoding (or fallback), and writes test header, channel header, and channel data via `TestHeader.WriteTestHeader`, `ChannelHeader.WriteChannelHeaderToString`, and `ChannelData.GenerateChannelData`/`WriteChannelData`.
|
||||
- **`Initialize(...)`**
|
||||
Empty stub method (no-op). Present to satisfy `IWriter<Test>` interface but performs no initialization.
|
||||
|
||||
### `DTS.Serialization.TDM.TestHeader`
|
||||
- **`WriteTestHeader(Writer writer, TextWriter tw, bool bFiltered, UInt16 subSampleInterval, ulong numSamples, int preTriggerSamples)`**
|
||||
Writes the test header section to the CSV. Includes test ID, impact parameters (hardcoded to 0), date/time, device sections (dummies, barriers, groups), sample counts, sample rate, channel count, and description. Device section writing is partially implemented (dummies use `UserValue3` from first channel; barriers/groups are written as blank lines).
|
||||
|
||||
### `DTS.Serialization.TDM.ChannelHeader`
|
||||
- **`WriteChannelHeaderToString(Writer writer, TextWriter tw, bool bFiltered, double start, double end)`**
|
||||
Writes the channel header section (15 lines) to the CSV. For each non-squib-voltage channel, populates fields: DAS name, capacity, engineering units, sensor SN, sensitivity, excitation, min/max values (computed over requested range), Toyota calc fields (hardcoded), knee point (from `SoftwareFilter`), data flag, channel code, and channel description. Squib voltage channels are skipped.
|
||||
|
||||
### `DTS.Serialization.TDM.TDMParameterDlg`
|
||||
- **`TDMParameterDlg(string testName, double testStart, double testEnd)`**
|
||||
Constructor. Initializes the dialog with test metadata. Sets default location to `TDMFolder` setting + `{testName}.csv`. Sets `tbStart`/`tbStop` text to either provided values (converted to ms) or user defaults, enforcing min/max constraints from `testStart`/`testEnd`.
|
||||
- **`FileName` (property, `string`)**
|
||||
Gets the selected output file path from `tbLocation.Text`.
|
||||
- **`Start` (property, `double`)**
|
||||
Gets the parsed start time in **seconds** (value in `tbStart` is in ms, divided by 1000).
|
||||
- **`Stop` (property, `double`)**
|
||||
Gets the parsed stop time in **seconds** (value in `tbStop` is in ms, divided by 1000).
|
||||
- **`btnBrowse_Click`**
|
||||
Opens a `SaveFileDialog` to select the output `.csv` file.
|
||||
- **`btnOK_Click`**
|
||||
Validates inputs: parses `tbStart`/`tbStop` as doubles, checks `Stop > Start`, ensures values are within `[testStart*1000, testEnd*1000]` ms range, saves settings, and sets `DialogResult = OK`.
|
||||
- **`btnCancel_Click`**
|
||||
Sets `DialogResult = Cancel` and closes the dialog.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **File format**: Output is always a `.csv` file named `{Test.Id}[optional suffix].csv`.
|
||||
- **Time units**: `Start`/`Stop` in `File`, `Writer`, and `TDMParameterDlg` properties are in **seconds**, except `TDMParameterDlg` UI fields (`tbStart`, `tbStop`) which display and parse values in **milliseconds**.
|
||||
- **Rounding**: `Start` and `Stop` passed to `DoExport` are rounded to 3 decimal places (milliseconds precision) before use.
|
||||
- **Channel filtering**: Squib voltage channels (`IsSquibVoltage() == true`) are excluded from channel header and data export.
|
||||
- **Sample bounds**: Exported sample indices are clamped to `[StartRecordSampleNumber, StartRecordSampleNumber + NumberOfSamples)` per module. Invalid ranges are silently adjusted.
|
||||
- **Encoding**: Output uses UTF-8 with BOM by default; falls back to `Encoding.Default` on encoding errors.
|
||||
- **Device section constraints**: `TestHeader` enforces `MAX_DEVICE_LINES = 23` total device lines (dummies, barriers, groups), with specific max counts (`MAX_DUMMY_DISPLAY=16`, `MAX_BARRIER_DISPLAY=3`, `MAX_OLD_GROUP_LINES=4`). Device lists are padded with empty lines to fill allocated space.
|
||||
- **Progress reporting**: `IncrementLevel` is dynamically set to `10`, `1000`, or `10000` based on estimated sample count to ensure progress ticks fit within `uint` limits.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Internal Dependencies
|
||||
- **`DTS.Common.DAS.Concepts`**: Provides `Test`, `Test.Module`, `Test.Module.Channel`, `Test.Module.AnalogInputChannel`, `FilteredData`, `DataScaler`.
|
||||
- **`DTS.Common.Utilities.Logging`**: Provides `APILogger`.
|
||||
- **`DTS.Common.Serialization`**: Base classes `Serialization.File`, `Serialization.File.Writer<File>`, `IWriter<Test>`, event handlers (`BeginEventHandler`, `EndEventHandler`, `TickEventHandler`, `ErrorEventHandler`, `CancelEventHandler`, `CancelRequested`).
|
||||
- **`DTS.Common.Enums.Sensors`**: `SensorConstants` (e.g., `BridgeType.IEPE`, `BridgeType.DigitalInput`).
|
||||
- **`DTS.Common.Utilities`**: `DescriptionAttributeCoder<T>`.
|
||||
- **`System`**: Core types (`System.IO`, `System.Text`, `System.Linq`, `System.Globalization`).
|
||||
- **`System.Windows.Forms`**: Used by `TDMParameterDlg` (`Form`, `SaveFileDialog`, `ErrorProvider`, `TableLayoutPanel`, `Button`, `TextBox`, `Label`).
|
||||
|
||||
### External Dependencies
|
||||
- **Settings**: Relies on `Properties.Settings1.Default.TDMFolder`, `DefaultStart`, `DefaultStop`.
|
||||
- **File system**: Requires write access to the output directory.
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **Time unit confusion**: `TDMParameterDlg` UI uses milliseconds, but `File.Start`/`Stop` and `Writer.Start`/`Stop` use seconds. Conversion is handled only in `TDMParameterDlg`'s `Start`/`Stop` properties (divide ms by 1000).
|
||||
- **Rounding hack**: `Start`/`Stop` are rounded to 3 decimal places in `Writer.Write` to mitigate floating-point precision issues from SLICE/TDAS download discrepancies. This may alter user-specified ranges slightly.
|
||||
- **Sample index calculation**: `ChannelHeader.WriteChannelHeaderToString` computes sample indices using `TriggerSampleNumbers[0]` and `StartRecordSampleNumber`. If these values are inconsistent across modules, sample ranges may be misaligned.
|
||||
- **Device section underutilization**: `TestHeader.WriteDeviceSection` writes dummies/barrriers/groups but often leaves many lines blank (e.g., dummies use only `UserValue3` from first channel; barriers/groups are hardcoded to 0 count). This is noted as "not completely implemented equivalent to TDM".
|
||||
- **Squib channel handling**: Squib voltage channels are skipped entirely in export. Squib channels (non-voltage) are included but with hardcoded capacity (`10`) and sensitivity (`1`).
|
||||
- **Min/max calculation**: `ChannelHeader.WriteChannelHeaderToString` computes min/max over the requested `start`/`end` range. If the range extends beyond available data, `IndexOutOfRangeException` is caught and logged, but min/max may be incomplete.
|
||||
- **Encoding fallback**: If `DefaultEncoding` is invalid, `Encoding.Default` is used silently (after logging), which may cause non-ASCII characters to be mangled.
|
||||
- **No-op `Initialize`**: The `Writer.Initialize` method is present but empty. Any initialization logic must be done elsewhere (e.g., in `Write`).
|
||||
- **Hardcoded values**: Several fields are hardcoded (e.g., impact speed/weight = 0, capacity for squib = 10, cable multiplier = 1, excitation for digital = 1V). These may not match all TDM variants.
|
||||
- **Filename construction**: Output filename is `Path.Combine(pathname, Test.Id)`, where `pathname` is treated as a directory. If `pathname` is a file path, behavior is undefined (likely creates nested path).
|
||||
@@ -0,0 +1,170 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/TDMS/TDMS.File.cs
|
||||
- Common/DTS.Common.Serialization/TDMS/TDMS.File.Writer.cs
|
||||
generated_at: "2026-04-16T03:37:03.448977+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "d8ac04ef5386bd66"
|
||||
---
|
||||
|
||||
# TDMS
|
||||
|
||||
## Documentation: TDMS.File Module
|
||||
|
||||
---
|
||||
|
||||
### **Purpose**
|
||||
|
||||
This module implements serialization and deserialization logic for the TDMS (Technical Data Management Streaming) file format, a binary format used primarily for storing time-series test data. It defines the `DTS.Serialization.TDMS.File` class, which represents a TDMS file and encapsulates metadata and configuration (e.g., filtering options, test plan association), and its nested `Writer` class, responsible for writing `Test` objects to disk in the NI TDMS v2.0 format (as referenced by the whitepaper URL in comments). The module serves as the core serialization backend for exporting test data in a standardized, interoperable format compatible with National Instruments tools.
|
||||
|
||||
---
|
||||
|
||||
### **Public Interface**
|
||||
|
||||
#### **Class: `DTS.Serialization.TDMS.File`**
|
||||
|
||||
- **Constructor**
|
||||
```csharp
|
||||
public File(Common.ISO.TestPlan plan)
|
||||
```
|
||||
Initializes a new `File` instance, associating it with a given `TestPlan`. Calls `base("TDMS")`, indicating it inherits from `Serialization.File`.
|
||||
|
||||
- **Properties**
|
||||
- `public static string Extension => ".tdms"`
|
||||
Returns the file extension for TDMS files.
|
||||
- `public bool UseZeroForUnfiltered { get; set; } = false`
|
||||
Controls whether unfiltered data should be represented as zero (default: `false`).
|
||||
- `public bool FilteredExport { get; set; } = false`
|
||||
Indicates whether filtered data export is enabled (default: `false`).
|
||||
- `public IWriter<Test> Exporter { get; }`
|
||||
Lazily initializes and returns a `Writer` instance associated with this `File`. Sets `Writer.TestPlan` and `Writer.WriterParent` appropriately. Throws a wrapped exception on failure.
|
||||
|
||||
- **Methods**
|
||||
- `public override void SetEUData(string channelId, FilteredData fd)`
|
||||
Stores or updates Eu (engineering units) unfiltered data for a given channel ID in an internal dictionary `_EUUnfilteredDataForLinearizedChannels`.
|
||||
- `public override FilteredData GetEUData(string channelId)`
|
||||
Retrieves stored Eu unfiltered data for a given channel ID from `_EUUnfilteredDataForLinearizedChannels`. Returns `null` if not present.
|
||||
|
||||
> **Note**: `_EUUnfilteredDataForLinearizedChannels` is a private `Dictionary<string, FilteredData>`, used to associate channel IDs with precomputed Eu data (likely for linearized channels).
|
||||
|
||||
---
|
||||
|
||||
#### **Nested Class: `DTS.Serialization.TDMS.File.Writer`**
|
||||
|
||||
- **Constructor**
|
||||
```csharp
|
||||
internal Writer(File fileType, int encoding)
|
||||
```
|
||||
Internal constructor; initializes the base `Writer<File>` with the parent `File` and encoding. The `encoding` parameter is passed to the base class.
|
||||
|
||||
- **Properties**
|
||||
- `public File WriterParent { get; set; }`
|
||||
Reference back to the parent `File` instance. Set by `File.Exporter` getter.
|
||||
- `public Common.ISO.TestPlan TestPlan { get; set; } = null`
|
||||
Reference to the test plan associated with the export. Set by `File.Exporter`.
|
||||
- `public string ExtensionPrefix { get; set; } = string.Empty`
|
||||
Optional prefix appended to the base filename (e.g., for multi-file exports).
|
||||
|
||||
- **Methods**
|
||||
- `public void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)`
|
||||
Convenience overload of `Write(...)`. Delegates to the 18-parameter overload with many arguments set to `null` or defaults.
|
||||
- `public void Write(string pathname, string id, string dataFolder, Test test, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Test.Module.Channel tmChannel, int channelNumber, BeginEventHandler beginEventHandler, CancelEventHandler cancelEventHandler, EndEventHandler endEventHandler, TickEventHandler tickEventHandler, ErrorEventHandler errorEventHandler, CancelRequested cancelRequested, double minStartTime, int dataCollectionLength)`
|
||||
Main export method. Writes a `Test` to disk as a `.tdms` file.
|
||||
- Creates the target directory if missing.
|
||||
- Constructs filename as `Path.Combine(pathname, id + ExtensionPrefix + ".tdms")`.
|
||||
- Writes a binary stream using `BinaryWriter`.
|
||||
- Invokes event handlers (`begin`, `tick`, `end`, `error`) for progress/error reporting.
|
||||
- Calls `WriteLeadInAndMetaData(...)` and `WriteRawData(...)` to serialize metadata and raw data.
|
||||
- Logs exceptions via `APILogger.Log(...)`.
|
||||
- Throws or reports exceptions depending on presence of `errorEventHandler`.
|
||||
- `public void Initialize(...)`
|
||||
Currently empty stub. No-op implementation.
|
||||
|
||||
> **Note**: `BeginEventHandler`, `CancelEventHandler`, `EndEventHandler`, `TickEventHandler`, `ErrorEventHandler`, and `CancelRequested` are delegate/event types used for progress reporting but are not defined in this file.
|
||||
|
||||
---
|
||||
|
||||
### **Invariants**
|
||||
|
||||
1. **File Format Compliance**:
|
||||
- The written file adheres to the NI TDMS v2.0 format (per [NI whitepaper 3727](http://www.ni.com/white-paper/3727/en/)).
|
||||
- The lead-in signature is always `"TDSm"` (4 bytes).
|
||||
- The `ToCMask` is fixed to `14` (`TocMetaData | TocNewObjList | TocRawData`).
|
||||
- The file version is fixed to `4713`.
|
||||
- All numeric fields use little-endian encoding (no big-endian support; `TocBigEndian` bit is unset).
|
||||
|
||||
2. **Data Layout**:
|
||||
- Raw data is stored as 16-bit signed integers (`DataTypes.I16`), regardless of source data type.
|
||||
- Each channel’s raw data is written sequentially, with no interleaving.
|
||||
- The raw data offset and next segment offset are computed and written as 8-byte unsigned integers.
|
||||
|
||||
3. **Metadata Structure**:
|
||||
- Exactly four objects are written:
|
||||
1. File object (`"/"`),
|
||||
2. Group object (`"/'TestId'"`),
|
||||
3. One channel object per `test.Channels`.
|
||||
- Group properties are always written in the order defined by `GroupProperties` enum (TestId, Description, TestDate, TestTime).
|
||||
- Channel properties are written in the order defined by `ChannelProperties` enum.
|
||||
|
||||
4. **String Encoding**:
|
||||
- Strings are written as UTF-16 (via `char[]` → `BinaryWriter.Write(char[])`), with length prefix (4 bytes).
|
||||
- SuperScript characters (e.g., in `LinearizationFormula`) increase the string’s byte length beyond the character count (handled by `GetSuperScriptBytes`).
|
||||
|
||||
---
|
||||
|
||||
### **Dependencies**
|
||||
|
||||
- **Internal Dependencies**
|
||||
- `DTS.Serialization.Test` (type `Test`, `Test.Module.Channel`, `Test.Module.AnalogInputChannel`, `Test.Module`)
|
||||
- `DTS.Serialization.TDMS.FilteredData` (used in `SetEUData`/`GetEUData`)
|
||||
- `DTS.Common.ISO.TestPlan` (passed to constructor)
|
||||
- `DTS.Common.Utilities.Logging.APILogger` (used for logging exceptions)
|
||||
|
||||
- **External Dependencies**
|
||||
- `System.IO` (`FileStream`, `BinaryWriter`, `Directory`, `Path`)
|
||||
- `System.Linq` (used for LINQ queries in `GetChannelPropertyLengths`)
|
||||
- `System.Collections.Generic` (`Dictionary`, `HashSet`, `List`, `Enum.GetValues`)
|
||||
|
||||
- **Inheritance & Interfaces**
|
||||
- `File` inherits from `Serialization.File` (base class).
|
||||
- `File` implements `IWritable<Test>`.
|
||||
- `Writer` inherits from `Writer<File>` (generic base class) and implements `IWriter<Test>`.
|
||||
|
||||
---
|
||||
|
||||
### **Gotchas**
|
||||
|
||||
1. **Hardcoded Data Type**:
|
||||
Raw data is *always* written as `I16` (`DataTypes.I16`), even if the underlying `PersistentChannelInfo[i]` values are larger or different types. This may cause data truncation if values exceed `Int16` range.
|
||||
|
||||
2. **SuperScript Byte Counting Quirk**:
|
||||
The `GetSuperScriptBytes` method computes extra bytes for certain Unicode super/subscript characters (e.g., `⁰`, `²`, `ⁿ`) in `LinearizationFormula`. This logic assumes UTF-16 encoding and checks specific byte patterns (`byteArray[0]`, `byteArray[1]`). This is non-standard and may break if the source strings contain unexpected Unicode.
|
||||
|
||||
3. **Unused Parameters in `Write(...)` Overloads**:
|
||||
Several parameters in the 18-argument `Write(...)` overload (`dataFolder`, `fd`, `tmChannel`, `channelNumber`, `minStartTime`, `dataCollectionLength`) are *not used* in the implementation. Their presence suggests partial refactoring or future extensibility.
|
||||
|
||||
4. **Empty `Initialize(...)` Method**:
|
||||
The `Initialize(...)` method is a no-op stub. Its signature implies it may have been intended for streaming or multi-pass writes but is currently unused.
|
||||
|
||||
5. **No Support for Event Cancellation**:
|
||||
Although `CancelRequested` and `CancelEventHandler` are passed to `Write(...)`, the method does not check for cancellation during iteration over samples. Progress reporting (`tickEventHandler`) occurs only once (at 100%) after full write.
|
||||
|
||||
6. **String Concatenation in Paths**:
|
||||
Channel object paths are built via string concatenation (e.g., `groupObjectPath + "/" + "'" + channelName + "':" + description + "'"`). This assumes no special characters (e.g., quotes, slashes) in `channel.ChannelName2` or `channel.ChannelDescriptionString`, which could break path parsing.
|
||||
|
||||
7. **No Validation of Input Data**:
|
||||
The `WriteRawData` method writes raw samples directly without validation. If `PersistentChannelInfo.NumberOfSamples` is inconsistent with actual data length, it may cause `IndexOutOfRangeException` or silent truncation.
|
||||
|
||||
8. **Hardcoded Property Lists**:
|
||||
Property lists (`GroupProperties`, `ChannelProperties`) are fixed via `Enum.GetValues`. Adding new properties requires updating the enum *and* all switch statements in `WriteGroupProperties` and `WriteChannelSection`.
|
||||
|
||||
9. **No Support for Multiple Segments or Append Mode**:
|
||||
The implementation writes a single segment with fixed `nextSegmentOffset = RawDataOffset + totalNumberRawDataBytes`. It does not support appending to existing TDMS files or multi-segment files.
|
||||
|
||||
10. **Encoding Assumption**:
|
||||
The `encoding` parameter passed to `Writer` constructor is used only in the base class. No explicit encoding configuration (e.g., UTF-8 vs UTF-16) is exposed or validated in this module.
|
||||
|
||||
---
|
||||
|
||||
*End of Documentation.*
|
||||
290
enriched-qwen3-coder-next/Common/DTS.Common.Serialization/TSV.md
Normal file
290
enriched-qwen3-coder-next/Common/DTS.Common.Serialization/TSV.md
Normal file
@@ -0,0 +1,290 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/TSV/TSV.File.cs
|
||||
- Common/DTS.Common.Serialization/TSV/TSVTest.cs
|
||||
- Common/DTS.Common.Serialization/TSV/TSVSettingsWindow.cs
|
||||
- Common/DTS.Common.Serialization/TSV/TSV.File.Writer.cs
|
||||
- Common/DTS.Common.Serialization/TSV/TSVChannel.cs
|
||||
- Common/DTS.Common.Serialization/TSV/TSVSettingsWindow.Designer.cs
|
||||
generated_at: "2026-04-16T03:37:39.731029+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "ac1bf0260831585c"
|
||||
---
|
||||
|
||||
# TSV Serialization Module Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides serialization support for test data in Tab-Separated Values (TSV) format. It defines the core types (`File`, `TSVTest`, `TSVChannel`) for representing test metadata and channel data in a structured TSV schema, along with a `Writer` class for exporting `Test` objects to disk. The module also includes a UI form (`TSVSettingsWindow`) for interactive configuration of TSV export parameters. It serves as the backend for exporting test data to human-readable TSV files, primarily for interoperability with external tools (e.g., Excel, TTC), and integrates with application settings to persist last-used field values.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### `DTS.Serialization.TSV.File`
|
||||
|
||||
- **`File()`**
|
||||
Constructor. Initializes a new instance of the `File` class, passing `"TSV"` to the base `Serialization.File` constructor.
|
||||
|
||||
- **`static string Extension`**
|
||||
Returns the file extension for this format: `".tsv"`.
|
||||
|
||||
- **`IWriter<Test> Exporter`**
|
||||
Gets the writer instance for this file type. Lazily initializes `_Exporter` using `DefaultEncoding` if not already created. Throws an `Exception` with inner exception if initialization fails.
|
||||
|
||||
### `DTS.Serialization.TSV.TSVTest`
|
||||
|
||||
- **`TSVTest(Test test, FilteredData[] euFiltered, FilteredData[] adc, FilteredData[] euUnfiltered, string path, double[] actualRangesEUFiltered, double[] actualRangesEUUnfiltered, double[] actualRAngesADC)`**
|
||||
Constructor. Populates the test metadata from the provided `Test` object and raw data arrays. Initializes `_channels` for each channel in `test.Channels`. Sets default values for several fields (e.g., `TestNumber`, `TestDate`, `TestTime`, `SamplingRate`, `AAFilterCutoffDescription`) and loads persisted settings (e.g., `TSVPOCNameLastUsed`) into corresponding fields.
|
||||
|
||||
- **`string GetValue(TSVTest.Fields field)`**
|
||||
Returns the string value for the specified `field`. If the field has no value, returns `"#NOVALUE"`.
|
||||
|
||||
- **`void SetValue(TSVTest.Fields field, string value)`**
|
||||
Sets the value for the specified `field` in the global metadata. Additionally, propagates the value to all `_channels` and persists specific fields (`POCName`, `POCPhoneAndEmail`, `DataType`, `LabName`, `TestObject`, `TestType`) to `Properties.Settings1.Default`.
|
||||
|
||||
- **`TSVChannel[] Channels`**
|
||||
Gets or sets the array of `TSVChannel` instances associated with this test.
|
||||
|
||||
- **`Test Test`**
|
||||
Reference to the original `Test` object.
|
||||
|
||||
- **`FilteredData[] DataFilteredEU`**, **`DataUnfilteredEU`**, **`DataADC`**
|
||||
References to the filtered engineering units, unfiltered engineering units, and raw ADC data arrays, respectively.
|
||||
|
||||
- **`double[] ActualRangesEUFiltered`**, **`ActualRangesEUUnfiltered`**, **`ActualRangesADC`**
|
||||
Arrays of actual measurement ranges (in engineering units or ADC counts) for each channel.
|
||||
|
||||
### `DTS.Serialization.TSV.TSVChannel`
|
||||
|
||||
- **`string GetValue(TSVTest.Fields field)`**
|
||||
Returns the string value for the specified `field`. If the field has no value, returns `"#NOVALUE"`.
|
||||
|
||||
- **`void SetValue(TSVTest.Fields field, string value)`**
|
||||
Sets the value for the specified `field`. Includes special handling for `DataType`:
|
||||
- `"Raw"` → sets `EngineeringUnits` to `"ADC"`, clears `DigitalFilterType`, computes `BitResolution` from `ActualRangesADC`, and sets `FileName` to `.../TSV/Raw/{TestId}_{ChannelNumber}.TSV`.
|
||||
- `"Processed"` → sets `EngineeringUnits` to `_engineeringUnits`, computes `DigitalFilterType` from filtered data, computes `BitResolution` from `ActualRangesEUFiltered`, and sets `FileName` to `.../TSV/Processed/...`.
|
||||
- `"Converted"` → sets `EngineeringUnits` to `_engineeringUnits`, clears `DigitalFilterType`, computes `BitResolution` from `ActualRangesEUUnfiltered`, and sets `FileName` to `.../TSV/Converted/...`.
|
||||
|
||||
- **`string FileName`**
|
||||
Gets or sets the full path to the TSV file for this channel.
|
||||
|
||||
- **`int ChannelNumber`**
|
||||
Returns `1 + _channelIndex`.
|
||||
|
||||
- **`void Serialize(TickEventHandler tickHandler)`**
|
||||
Writes the channel’s TSV file to `FileName`. Creates the directory if needed. Writes metadata fields (title + value) followed by time-value pairs (time in seconds, data value). Uses `Truncate` to limit time precision based on sample rate. Invokes `tickHandler` periodically (every 1000 samples) with progress percentage.
|
||||
|
||||
### `DTS.Serialization.TSV.TSVSettingsWindow`
|
||||
|
||||
- **`TSVSettingsWindow(TSVTest test)`**
|
||||
Constructor. Populates two grids:
|
||||
- `c1GridGlobal`: Displays editable rows for non-hidden `TSVTest.Fields` (excludes `AAFilterCutoffDescription`, `BitResolution`, `ChannelErrors`, `DataType`, `DigitalFilterType`, `EngineeringUnits`, `SensorAxis`, `SensorLocation`, `SensorMakeModelSerial`, `SensorMountType`). Values come from `test.GetValue(field)`.
|
||||
- `c1GridChannels`: Displays channel-specific data with columns for `ChannelNumber`, `FileName`, and all non-hidden fields.
|
||||
Initializes grid styles from `Properties.Settings1.Default`.
|
||||
|
||||
- **`button1_Click`**
|
||||
Sets `DialogResult = DialogResult.OK` and closes the window.
|
||||
|
||||
- **`c1GridGlobal_AfterEdit`**
|
||||
Updates `_test` with the new value for the edited global field. Propagates the change to all channels and updates the corresponding `c1GridChannels` rows.
|
||||
|
||||
- **`c1GridChannels_AfterEdit`**
|
||||
Updates the specific `TSVChannel` instance with the new value for the edited field.
|
||||
|
||||
### `DTS.Serialization.TSV.File.Writer`
|
||||
|
||||
- **`internal Writer(File fileType, int encoding)`**
|
||||
Constructor. Initializes the writer with the associated `File` instance and encoding.
|
||||
|
||||
- **`ExportMode CurrentExportMode`**
|
||||
Gets/sets the export mode (`FtssExcel`, `Ttc`, or `Standard`). Default: `FtssExcel`.
|
||||
|
||||
- **`List<FilteredData> FilteredChannelData`**
|
||||
Gets/sets the list of filtered channel data to use during export.
|
||||
|
||||
- **`void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)`**
|
||||
**Throws `NotSupportedException`** with message `"TSV::File::Writer Write(pathname, id, test, bFiltering) not supported"`.
|
||||
|
||||
- **`void Write(string pathname, string id, string dataFolder, Test test, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Test.Module.Channel tmChannel, int channelNumber, BeginEventHandler beginEventHandler, CancelEventHandler cancelEventHandler, EndEventHandler endEventHandler, TickEventHandler tickEventHandler, ErrorEventHandler errorEventHandler, CancelRequested cancelRequested, double minStartTime, int dataCollectionLength)`**
|
||||
Writes TSV files for all channels in `MyTSVTest.Channels` by calling `channel.Serialize(tickEventHandler)` for each. Logs exceptions via `APILogger`. Invokes event handlers (`beginEventHandler`, `tickEventHandler`, `endEventHandler`, `errorEventHandler`) to report progress and errors.
|
||||
|
||||
- **`void Initialize(...)`**
|
||||
Empty implementation.
|
||||
|
||||
- **`double Start`**, **`double Stop`**, **`ushort SubSampleInterval`**, **`bool Filtered`**
|
||||
Public properties with no visible usage in the provided source.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **`TSVTest._values` and `TSVChannel._values`**
|
||||
Both use `Dictionary<Fields, string>` to store field values. `GetValue` ensures every field has a value by inserting `"#NOVALUE"` on first access.
|
||||
|
||||
- **`TSVChannel.FileName` is always set during construction**
|
||||
Based on `path`, `Test.Id`, and `ChannelNumber`, initially pointing to `.../TSV/Processed/...`.
|
||||
|
||||
- **`TSVChannel.SetValue(Fields.DataType, ...)` triggers recomputation of `FileName`, `EngineeringUnits`, `DigitalFilterType`, and `BitResolution`**
|
||||
The new values depend on the `DataType` (`"Raw"`, `"Processed"`, or `"Converted"`) and the corresponding data/range arrays in `_parentTest`.
|
||||
|
||||
- **`TSVTest.SetValue` propagates changes to all channels**
|
||||
When a field is set globally, `SetValue` calls `channel.SetValue(field, value)` for every channel.
|
||||
|
||||
- **`TSVTest` fields `TestNumber`, `TestDate`, `TestTime`, `SamplingRate`, `AAFilterCutoffDescription` are set during construction**
|
||||
Derived from the `Test` object and its first module.
|
||||
|
||||
- **`TSVChannel.ChannelNumber` is 1-indexed**
|
||||
Computed as `1 + _channelIndex`.
|
||||
|
||||
- **`TSVChannel.Serialize` writes time-value pairs**
|
||||
Time is computed as `dStartTime + i / SampleRateHz`, truncated to a precision based on `SampleRateHz`. Data source depends on `DataType`.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Dependencies *of* this module:
|
||||
- **`DTS.Common.Utilities.DotNetProgrammingConstructs.Property<T>`**
|
||||
Used in `File.Writer` for `_CurrentExportMode` and `_FilteredChannelData`.
|
||||
- **`DTS.Common.Utilities.Logging.APILogger`**
|
||||
Used in `File.Writer.Write` for logging exceptions.
|
||||
- **`DTS.Serialization.Test`**
|
||||
Referenced in `TSVTest`, `TSVChannel`, and `File.Writer`. Provides test metadata and channel data.
|
||||
- **`DTS.Serialization.FilteredData`**
|
||||
Used in `TSVTest` and `TSVChannel` to hold processed data arrays.
|
||||
- **`System.IO`**
|
||||
Used for file/directory operations (`StreamWriter`, `Directory.CreateDirectory`, `Path.Combine`).
|
||||
- **`System.Windows.Forms`**
|
||||
Used in `TSVSettingsWindow` and its designer.
|
||||
- **`C1.Win.C1FlexGrid`**
|
||||
Used for grid controls (`c1GridGlobal`, `c1GridChannels`).
|
||||
- **`Properties.Settings1.Default`**
|
||||
Used to persist and retrieve last-used values for several fields (`TSVPOCNameLastUsed`, etc.).
|
||||
- **`TSVStrings.ResourceManager`**
|
||||
Used to retrieve localized titles/descriptions for fields (e.g., `"{field}_Title"`, `"{field}_Description"`).
|
||||
|
||||
### Dependencies *on* this module:
|
||||
- **`Serialization.File`**
|
||||
`TSV.File` inherits from `Serialization.File`.
|
||||
- **`IWritable<Test>`**
|
||||
Implemented by `TSV.File`.
|
||||
- **`IWriter<Test>`**
|
||||
Implemented by `TSV.File.Writer`.
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **`File.Writer.Write(...)` overload with 9 parameters is the only supported write path**
|
||||
The 7-parameter overload throws `NotSupportedException`. The 16-parameter overload is the functional entry point.
|
||||
|
||||
- **`TSVChannel.FileName` is overwritten on `DataType` change**
|
||||
Changing `DataType` via `SetValue` immediately updates `FileName` and other derived fields, which may be unexpected if called multiple times.
|
||||
|
||||
- **`TSVChannel.Serialize` uses `Encoding.Default`**
|
||||
This may produce non-portable encodings depending on the system locale.
|
||||
|
||||
- **`TSVChannel.Serialize` truncates time values**
|
||||
Precision is based on `SampleRateHz` (`decimalplaces = ceil(log10(SampleRateHz))`), which may cause rounding artifacts for high sample rates.
|
||||
|
||||
- **`TSVTest.SetValue` persists only 6 fields to settings**
|
||||
Only `POCName`, `POCPhoneAndEmail`, `DataType`, `LabName`, `TestObject`, and `TestType` are persisted; others are not.
|
||||
|
||||
- **`TSVChannel` constructor assumes `Test.Channels[i]` is an `AnalogInputChannel`**
|
||||
Casts to `Test.Module.AnalogInputChannel` without checking; may throw `InvalidCastException` if not.
|
||||
|
||||
- **`TSVSettingsWindow` hides 10 fields from the UI**
|
||||
Fields like `EngineeringUnits`, `SensorLocation`, etc., are excluded from the global and channel grids, even though they are editable programmatically.
|
||||
|
||||
- **`TSVTest` constructor populates `_channels` only for `test.Channels.Count` channels**
|
||||
Assumes `euUnfiltered.Length >= test.Channels.Count`; no bounds check beyond the loop condition.
|
||||
|
||||
- **`TSVChannel.Serialize` uses `channel.ParentModule.StartRecordSampleNumber` and `TriggerSampleNumbers[0]`**
|
||||
May produce incorrect start times if trigger data is missing or malformed.
|
||||
|
||||
- **`TSVChannel.Serialize` assumes `DataADC`, `DataUnfilteredEU`, `DataFilteredEU` are non-null and indexed correctly**
|
||||
No validation of array lengths or indices beyond the loop.
|
||||
|
||||
- **`TSVSettingsWindow` uses `_bPopulating` to suppress event recursion**
|
||||
This flag prevents infinite loops during initialization but may mask issues if not managed carefully.
|
||||
|
||||
- **`TSV.File.Writer` has unused properties (`Start`, `Stop`, `SubSampleInterval`, `Filtered`)**
|
||||
No logic in the provided source uses these; may be legacy or incomplete.
|
||||
|
||||
- **`TSV.File.Exporter` caches `_Exporter`**
|
||||
Reuse of the same writer instance across multiple exports may cause issues if state (e.g., `CurrentExportMode`, `FilteredChannelData`) is not reset.
|
||||
|
||||
- **`TSVStrings.ResourceManager` is used but not defined in source**
|
||||
Its availability and behavior are assumed; no fallback or error handling is visible.
|
||||
|
||||
- **`TSVTest` constructor sets `SamplingRate` and `AAFilterCutoffDescription` from `test.Modules.First()`**
|
||||
Assumes at least one module exists; may throw `InvalidOperationException` if `Modules` is empty.
|
||||
|
||||
- **`TSVChannel.Serialize` writes time column first, then data column**
|
||||
The TSV format is metadata rows (field\tvalue) followed by time-value pairs, which may not be compatible with all TSV parsers expecting a header row.
|
||||
|
||||
- **`TSVChannel.Serialize` writes `#NOVALUE` if a field is unset**
|
||||
This literal string appears in the output file, which may be misinterpreted as data.
|
||||
|
||||
- **`TSVChannel` does not expose `_engineeringUnits` directly**
|
||||
It is set once in the constructor and used in `SetValue` for `DataType == "Processed"` or `"Converted"`, but not updated if changed later.
|
||||
|
||||
- **`TSVSettingsWindow` uses `c1GridChannels.Cols.Add()` to build columns dynamically**
|
||||
Column order depends on `Enum.GetValues` order, which is not guaranteed stable across .NET versions unless explicitly sorted.
|
||||
|
||||
- **`TSVTest` constructor sets `FileName` for all channels to `.../Processed/...` initially**
|
||||
This is overwritten if `DataType` is later changed via `SetValue`.
|
||||
|
||||
- **`TSVChannel.Serialize` uses `channel.ParentModule.NumberOfSamples`**
|
||||
Assumes all channels have the same number of samples; no validation.
|
||||
|
||||
- **`TSVChannel.Serialize` uses `channel` cast from `parentTest.Test.Channels[_channelIndex]`**
|
||||
Assumes the channel is an `AnalogInputChannel`; no fallback for digital channels.
|
||||
|
||||
- **`TSVSettingsWindow` does not validate user input**
|
||||
No checks for invalid field values (e.g., `DataType` not in `{"Raw", "Processed", "Converted"}`).
|
||||
|
||||
- **`TSVChannel` does not expose `FileName` as a settable property in the constructor**
|
||||
It is computed from `path`, `Test.Id`, and `ChannelNumber`; changing `path` later does not update `FileName`.
|
||||
|
||||
- **`TSVTest` constructor sets `AAFilterCutoffDescription` using `test.Modules.First().AaFilterRateHz`**
|
||||
May be `0` or invalid if not set; no validation.
|
||||
|
||||
- **`TSVChannel.Serialize` writes `#NOVALUE` for unset fields in metadata rows**
|
||||
This may cause issues for downstream parsers expecting only valid data.
|
||||
|
||||
- **`TSVChannel.Serialize` does not flush or dispose the `StreamWriter` explicitly beyond `using`**
|
||||
`using` ensures disposal, but no explicit flush is done before closing.
|
||||
|
||||
- **`TSVChannel.Serialize` uses `tickHandler(this, percent)` with `this` as sender**
|
||||
The `TickEventHandler` signature is not defined in the source; assumed to be `void(object sender, double percent)`.
|
||||
|
||||
- **`TSVChannel.Serialize` uses `percentageComplete + i * weight / channel.ParentModule.NumberOfSamples`**
|
||||
May produce inaccurate progress if channels have varying sample counts.
|
||||
|
||||
- **`TSVChannel` does not handle `#NOVALUE` in `FileName`**
|
||||
If `FileName` is not set correctly, `Serialize` may throw `DirectoryNotFoundException` or `IOException`.
|
||||
|
||||
- **`TSVSettingsWindow` does not validate `TSVChannel` or `TSVTest` before editing**
|
||||
No null checks for `_test` or `_test.Channels`.
|
||||
|
||||
- **`TSVChannel` does not validate `channelIndex`**
|
||||
Assumes `channelIndex < parentTest.Test.Channels.Count` and `channelIndex < data array lengths`.
|
||||
|
||||
- **`TSVChannel` does not validate `parentTest` arrays**
|
||||
Assumes `ActualRangesADC`, `DataFilteredEU`, etc., are non-null and indexed correctly.
|
||||
|
||||
- **`TSVChannel` does not validate `parentTest.Test.Channels[channelIndex]`**
|
||||
Assumes it is an `AnalogInputChannel`.
|
||||
|
||||
- **`TSVChannel` does not validate `parentTest.Test.Channels[channelIndex].ParentModule`**
|
||||
Assumes it is non-null and has valid `SampleRateHz`, `NumberOfSamples`, etc.
|
||||
|
||||
- **`TSVChannel` does not validate `parentTest.Test.Channels[channelIndex].ParentModule.TriggerSampleNumbers`**
|
||||
Assumes it has at least one element if `Count > 0`.
|
||||
|
||||
- **`TSVChannel` does not validate `parentTest.Test.Channels[channelIndex].ParentModule.StartRecordSampleNumber`**
|
||||
Assumes it is a valid sample number.
|
||||
|
||||
- **`TSVChannel` does not validate `parentTest.Test.Channels[channelIndex].EngineeringUnits`**
|
||||
Trims trailing whitespace but does not validate content.
|
||||
|
||||
- **`TSVChannel` does not validate `parentTest.ActualRangesADC[_channelIndex]`**
|
||||
Assumes it is a valid range.
|
||||
|
||||
- **`TSVChannel` does not validate `parentTest.DataFilteredEU[_channelIndex].FilterDescription` or `FilterFrequencyHz`**
|
||||
Assumes they are non
|
||||
@@ -0,0 +1,316 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/Test/IConvertable.cs
|
||||
- Common/DTS.Common.Serialization/Test/IntervalSec.cs
|
||||
- Common/DTS.Common.Serialization/Test/DasTimestamp.cs
|
||||
- Common/DTS.Common.Serialization/Test/Test.cs
|
||||
generated_at: "2026-04-16T03:35:54.397147+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "d172f5c36f1bfbab"
|
||||
---
|
||||
|
||||
# Documentation: `DTS.Serialization` Namespace – Serialization Types
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides core serialization infrastructure for test metadata in the DTS system, centered around the `Test` class and its associated types (`DasTimestamp`, `IntervalSec`, and the `IConvertable` interface). It enables structured XML serialization/deserialization of test metadata (e.g., test ID, description, modules, channels, DAS timestamps), supports equality comparison, and includes utilities for channel ordering and fault flag management. The module exists to standardize how test metadata is persisted, retrieved, and compared across the DTS ecosystem, particularly for interoperability with SLICEWare and internal tools.
|
||||
|
||||
---
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### `IConvertable` Interface
|
||||
*Defined in `IConvertable.cs`*
|
||||
|
||||
- **`Test ToDtsSerializationTest()`**
|
||||
Converts the implementing object into a `DTS.Serialization.Test` instance.
|
||||
|
||||
- **`void FromDtsSerializationTest(Test test, ReportErrors reportErrors)`**
|
||||
Initializes the implementing object using data from a `Test` instance. Errors encountered during conversion are reported via the `reportErrors` delegate.
|
||||
|
||||
> **Note**: `ReportErrors` is a delegate: `public delegate void ReportErrors(List<string> errors);`
|
||||
|
||||
---
|
||||
|
||||
### `Test` Class
|
||||
*Defined in `Test.cs`*
|
||||
|
||||
- **Constructors**
|
||||
- `Test()`
|
||||
Default constructor. Initializes `InceptionDate` to `DateTime.Now`, calls `TryGetChannelOrder()`, and leaves `Id` and `Description` empty.
|
||||
- `Test(string dtsfile)`
|
||||
Placeholder constructor (empty implementation).
|
||||
- `Test(string id, string description)`
|
||||
Initializes with `id`, `description`, and `EventNumber = 0`.
|
||||
- `Test(string id, string description, int eventNumber)`
|
||||
Initializes with `id`, `description`, and `eventNumber`.
|
||||
|
||||
- **Properties**
|
||||
- `string Software` → `"DataPRO"` by default (read/write, XML-serialized as `"Software"`).
|
||||
- `string SoftwareVersion` → `""` by default (read/write, XML-serialized as `"SoftwareVersion"`).
|
||||
- `DateTime InceptionDate` → `DateTime.Now` by default (read/write).
|
||||
- `string Id` → `""` by default (read/write, XML-serialized as `"Id"`).
|
||||
- `string Description` → `""` by default (read/write, XML-serialized as `"Description"`).
|
||||
- `int EventNumber` → `0` by default (read/write, XML-serialized as `"EventNumber"`).
|
||||
- `Guid Guid` → `Guid.Empty` by default (read/write, XML-serialized as `"Guid"`).
|
||||
- `ushort FaultFlags` → `0` by default (read/write, XML-serialized as `"FaultFlags"`).
|
||||
- `uint ExtendedFaultFlags1–4` → `0` by default (read/write, XML-serialized as `"ExtendedFaultFlags1"`–`"ExtendedFaultFlags4"`).
|
||||
- `bool InlineSerializedData` → `false` by default (read/write, XML-serialized as `"InlineSerializedData"`; setting it propagates to all `Modules`).
|
||||
- `List<Module> Modules` → empty list by default (read/write, XML-serialized as `"Modules"`).
|
||||
- `List<DasTimestamp> DasTimestamps` → empty list by default (read/write, XML-serialized as `"DasTimestamps"`).
|
||||
- `List<Module.Channel> Channels` → computed list of all channels (including calculated channels) from `Modules`, sorted by `AbsoluteDisplayOrder`, then `ParentModule.Number`, then `Channel.Number`, and finally by `ChannelOrder.txt` if present.
|
||||
|
||||
- **Methods**
|
||||
- `void ClearExtendedFaultFlags()`
|
||||
Resets `ExtendedFaultFlags1`–`4` to `0`.
|
||||
- `void TryGetChannelOrder()`
|
||||
Attempts to load channel ordering from `"ChannelOrder.txt"` (if present) into an internal dictionary `_channelOrder`. Logs exceptions via `APILogger`.
|
||||
- `void SaveTest(string directory, string testId, int defaultEncoding, bool includeGroupNameInISOExport)`
|
||||
Saves test metadata to a `.dts` file. Backs up existing `.dts` file (if no `.bak` exists), writes SLICEWare-compatible data via `SliceRaw.File.Exporter.Write(...)`, then appends XML-serialized `<Test>` metadata (using `WriteXml`) in UTF-16 encoding. Deletes backup on successful save.
|
||||
- `void WriteXml(XmlWriter writer)`
|
||||
Serializes the `Test` instance to XML using attributes tagged with `[XmlSerializationTag]`. Writes attributes for top-level properties, then `<Modules>` and `<DasTimestamps>` elements with nested content.
|
||||
- `void ReadXml(XmlReader reader)`
|
||||
Deserializes XML into the `Test` instance. Reads attributes for top-level properties, then deserializes `<Module>` and `<DasTimestamp>` children using their respective `ReadXml` methods. Uses `ReadSubtree()` to isolate child element parsing.
|
||||
- `XmlSchema GetSchema()`
|
||||
Returns `null` (per comment, this method is never invoked during serialization).
|
||||
- `override bool Equals(object obj)`
|
||||
Compares `Id`, `Description`, and `Modules` (via private helper `ModulesEquals`) for equality.
|
||||
- `override int GetHashCode()`
|
||||
Returns `base.GetHashCode()` (no custom hashing logic).
|
||||
|
||||
> **Note**: `ModulesEquals` compares two `List<Module>` by count and element-wise `Equals`.
|
||||
|
||||
---
|
||||
|
||||
### `DasTimestamp` Class
|
||||
*Defined in `DasTimestamp.cs`*
|
||||
|
||||
- **Constructor**
|
||||
- `DasTimestamp(Test parentTest)`
|
||||
Initializes with a reference to the parent `Test` instance.
|
||||
|
||||
- **Properties**
|
||||
- `Test ParentTest` → `null` by default (read-only, set only via constructor).
|
||||
- `string BaseSerialNumber` → `""` by default (read/write, XML-serialized as `"BaseSerialNumber"`).
|
||||
- `UInt64 NumberOfSamples` → `0` by default (read/write, XML-serialized as `"NumberOfSamples"`).
|
||||
- `UInt32 NumberOfBitsPerSample` → `0` by default (read/write, XML-serialized as `"NumberOfBitsPerSample"`).
|
||||
- `string FileName` → `""` by default (read/write, XML-serialized as `"FileName"`).
|
||||
|
||||
- **Methods**
|
||||
- `void WriteXml(XmlWriter writer)`
|
||||
Serializes `BaseSerialNumber`, `NumberOfSamples`, and `NumberOfBitsPerSample` as XML attributes. Writes `BaseSerialNumber` as `"NA"` if conversion fails. *Does not serialize `FileName` or `NumberOfBitsPerSample` in XML output* (only reads `NumberOfBitsPerSample`; defaults to `8 * sizeof(ulong)` if missing).
|
||||
- `void ReadXml(XmlReader reader)`
|
||||
Reads `BaseSerialNumber`, `NumberOfSamples`, and `NumberOfBitsPerSample` from attributes. Sets `NumberOfBitsPerSample` to `8 * sizeof(ulong)` (i.e., `64`) if missing or unparseable.
|
||||
- `XmlSchema GetSchema()`
|
||||
Returns `null`.
|
||||
- `override bool Equals(object obj)`
|
||||
Compares `FileName`, `NumberOfSamples`, `NumberOfBitsPerSample`, and `BaseSerialNumber`.
|
||||
- `override int GetHashCode()`
|
||||
Returns `base.GetHashCode()`.
|
||||
|
||||
---
|
||||
|
||||
### `IntervalSec` Class
|
||||
*Defined in `IntervalSec.cs`*
|
||||
|
||||
- **Constructors**
|
||||
- `IntervalSec()`
|
||||
Default constructor. Leaves `Begin` and `End` uninitialized (default `0.0`).
|
||||
- `IntervalSec(double begin, double end)`
|
||||
Initializes `Begin` and `End` to specified values. Wraps exceptions in a new `Exception`.
|
||||
|
||||
- **Properties**
|
||||
- `bool DoRoundOffValues` → `false` by default (read/write).
|
||||
- `int NumberRoundingDecimalPlaces` → `6` by default (read/write, via `Property<int>` wrapper).
|
||||
- `double Begin` → `0.0` by default (read/write).
|
||||
*Rounds to `NumberRoundingDecimalPlaces` if `DoRoundOffValues` is `true`.*
|
||||
- `double End` → `0.0` by default (read/write).
|
||||
*Rounds to `NumberRoundingDecimalPlaces` if `DoRoundOffValues` is `true`.*
|
||||
|
||||
- **Methods**
|
||||
- `override bool Equals(object obj)`
|
||||
Compares `Begin` and `End` using `double.Equals()`.
|
||||
- `override int GetHashCode()`
|
||||
Returns `base.GetHashCode()`.
|
||||
|
||||
> **Note**: `IntervalSec` inherits from `Exceptional` (not shown in source), which likely provides exception-handling infrastructure.
|
||||
|
||||
---
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **`Test.Id` and `Test.Description`**
|
||||
May be empty strings after default construction; no validation enforced.
|
||||
|
||||
- **`Test.Guid`**
|
||||
Defaults to `Guid.Empty`; no uniqueness guarantee is enforced by the class itself.
|
||||
|
||||
- **`Test.InceptionDate`**
|
||||
Always initialized to `DateTime.Now` in the default constructor.
|
||||
|
||||
- **`Test.Channels` ordering**
|
||||
Channels are sorted by:
|
||||
1. `AbsoluteDisplayOrder`
|
||||
2. `ParentModule.Number`
|
||||
3. `Channel.Number`
|
||||
...and *then* reordered by `ChannelOrder.txt` if present (via `ChannelOrderComparor`).
|
||||
**Critical**: If `ChannelOrder.txt` is missing or unreadable, only the first three criteria apply.
|
||||
|
||||
- **`DasTimestamp.NumberOfBitsPerSample`**
|
||||
Defaults to `64` (i.e., `8 * sizeof(ulong)`) if missing in XML during deserialization.
|
||||
|
||||
- **`Test.SaveTest` behavior**
|
||||
Backs up `.dts` file only if no `.bak` exists *at the time of save*. Backup is deleted on successful save.
|
||||
|
||||
- **XML attribute extraction**
|
||||
Uses `AttributeExtractor<XmlSerializationTagAttribute>` to map property names to XML attribute names. Property names must match exactly (e.g., `"BaseSerialNumber"` → attribute `"BaseSerialNumber"`).
|
||||
|
||||
---
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Internal Dependencies (from source)
|
||||
- `DTS.Common.Utilities`
|
||||
- `DotNetProgrammingConstructs.Property<T>`: Used for property wrappers with metadata (e.g., `Property<double>`, `Property<string>`).
|
||||
- `Logging.APILogger`: Used for logging exceptions (e.g., in `TryGetChannelOrder`, `SaveTest`).
|
||||
- `Xml.AttributeExtractor<T>`: Used to extract `[XmlSerializationTag]` attributes for XML serialization.
|
||||
- `DTS.Common.Utilities.Xml`
|
||||
- `SliceRaw.File` and `SliceRaw.File.Exporter`: Used in `Test.SaveTest` for SLICEWare-compatible export.
|
||||
- `System.Xml.Serialization`
|
||||
- `IXmlSerializable` interface (implemented by `Test` and `DasTimestamp`).
|
||||
- `System.Collections.Generic`
|
||||
- `Dictionary<string, int>` for channel ordering (`_channelOrder`).
|
||||
- `List<T>` for `Modules`, `DasTimestamps`, and `Channels`.
|
||||
|
||||
### External Dependencies (inferred)
|
||||
- `ChannelOrder.txt`: Required for channel ordering (loaded at runtime via `TryGetChannelOrder()`).
|
||||
- `APILogger`: External logging utility (not defined in source; assumed to be a static logger).
|
||||
- `SliceRaw.File.Exporter.Write(...)`: External serialization utility for SLICEWare compatibility.
|
||||
|
||||
### Inferred Consumers
|
||||
- Any code that needs to serialize/deserialize test metadata (e.g., `Test.SaveTest`, XML readers/writers).
|
||||
- Code that needs channel ordering (e.g., `Test.Channels`).
|
||||
- Code that converts custom objects to/from `Test` via `IConvertable`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **`IntervalSec` default constructor leaves `Begin`/`End` uninitialized**
|
||||
Though initialized to `0.0`, the comment warns this is "uninitialized". Callers must explicitly set values.
|
||||
|
||||
- **`DasTimestamp.WriteXml` omits `FileName` and `NumberOfBitsPerSample`**
|
||||
Only `BaseSerialNumber` and `NumberOfSamples` are written to XML. `NumberOfBitsPerSample` is *read* but not *written*. This asymmetry may cause data loss.
|
||||
|
||||
- **`Test.SaveTest` overwrites `.dts` in-place**
|
||||
Appends XML metadata to the *existing* `.dts` file (after SLICEWare data). If the original file is corrupted or truncated, this may cause issues.
|
||||
|
||||
- **`Test.SaveTest` uses UTF-16 for XML metadata**
|
||||
Hardcoded `Encoding.Unicode` (UTF-16) for appended XML. May conflict with SLICEWare’s expectations if it assumes ASCII/UTF-8.
|
||||
|
||||
- **`Test.Guid` and `Test.FaultFlags` use fallback defaults on deserialization**
|
||||
`Guid` defaults to `Guid.Empty` on parse failure; `FaultFlags` defaults to `0`. No error is raised.
|
||||
|
||||
- **`ExtendedFaultFlags1–4` are optional in XML**
|
||||
`GetUintSafe` returns `0` if attributes are missing or invalid. No warning is logged beyond `APILogger.Log` (non-fatal).
|
||||
|
||||
- **`IConvertable.FromDtsSerializationTest` passes `ReportErrors` but does not enforce error handling**
|
||||
The delegate is provided but not validated; callers may ignore errors.
|
||||
|
||||
- **`Test.Channels` sorting is order-dependent**
|
||||
`CompareChannels` is called first (for primary sort), *then* `ChannelOrderComparor` is applied. If `ChannelOrder.txt` is loaded, it overrides the primary sort order.
|
||||
|
||||
- **`TryGetChannelOrder` is not idempotent**
|
||||
`_channelOrder` is cleared on every call. If `ChannelOrder.txt` is modified during runtime, re-calling `TryGetChannelOrder()` is required to pick up changes.
|
||||
|
||||
- **`IntervalSec` rounding is applied only on `get`**
|
||||
`Begin`/`End` store raw values; rounding occurs only when accessed. This may cause `Begin != _Begin.Value` during serialization if `DoRoundOffValues` is `true`.
|
||||
|
||||
- **`Test.Equals` ignores `Guid`, `FaultFlags`, `Modules.Count`, and `DasTimestamps`**
|
||||
Only `Id`, `Description`, and `Modules` are compared. This is likely a bug or intentional simplification.
|
||||
|
||||
- **`Test.WriteXml` writes `Software`/`SoftwareVersion` as attributes, not elements**
|
||||
This is inconsistent with `Modules`/`DasTimestamps` (which are elements). Ensure consumers expect this.
|
||||
|
||||
- **`Test.ReadXml` uses `ReadSubtree()` for child deserialization**
|
||||
This isolates parsing but may fail if child `ReadXml` implementations do not consume all tokens in their subtree.
|
||||
|
||||
- **No validation for `IntervalSec.Begin >= End`**
|
||||
The class does not enforce that `Begin ≤ End`. Invalid intervals are allowed.
|
||||
|
||||
- **`Test` constructors do not initialize `Modules` or `DasTimestamps`**
|
||||
They are initialized via `Property<T>` defaults (empty lists), but the comment for `Test()` warns `Id`/`Description` are left empty. No other fields are explicitly initialized.
|
||||
|
||||
- **`DasTimestamp.ParentTest` is read-only**
|
||||
Set only in constructor; cannot be reassigned later.
|
||||
|
||||
- **`Test.InlineSerializedData` setter propagates to `Modules`**
|
||||
Modifying this property on `Test` updates all `Modules.InlineSerializedData`. This may cause unintended side effects if modules are shared or reused.
|
||||
|
||||
- **`GetUintSafe` swallows exceptions silently**
|
||||
Returns `defaultValue` on failure and logs via `APILogger`, but does not propagate errors.
|
||||
|
||||
- **`Test.SaveTest` deletes backup on success**
|
||||
If `SaveTest` fails partway (e.g., after backup but before final save), the backup may be left orphaned.
|
||||
|
||||
- **`IntervalSec.NumberRoundingDecimalPlaces` uses a `Property<int>` wrapper**
|
||||
This adds indirection but no additional behavior. The underlying value is mutable and not validated.
|
||||
|
||||
- **`Test.Guid` is serialized as a string**
|
||||
Uses `Guid.ToString()` (default format: `"D"`), which is standard but should be confirmed for compatibility.
|
||||
|
||||
- **`Test.Channels` includes `CalculatedChannels`**
|
||||
These are appended to `Channels` alongside regular `Channels`. Ensure consumers distinguish them if needed.
|
||||
|
||||
- **`DasTimestamp` uses `CultureInfo("")` (invariant culture)**
|
||||
This is appropriate for numeric serialization but may cause issues if XML attributes use locale-specific formatting.
|
||||
|
||||
- **`Test.SaveTest` appends metadata to `.dts` file**
|
||||
This assumes the `.dts` file is text-based and supports appending. Binary `.dts` files may be corrupted.
|
||||
|
||||
- **`Test.SaveTest` uses `StringWriter` without specifying encoding**
|
||||
`StringWriter` defaults to UTF-16, but `fileWriter` uses `Encoding.Unicode` (also UTF-16). This is consistent but unusual.
|
||||
|
||||
- **`Test.SaveTest` does not validate `testId` or `directory`**
|
||||
May throw `PathTooLongException`, `DirectoryNotFoundException`, or similar.
|
||||
|
||||
- **`Test.SaveTest` does not flush or close streams explicitly**
|
||||
Relies on `using` blocks, but `StreamWriter` disposal may not guarantee immediate disk write.
|
||||
|
||||
- **`Test.SaveTest` does not handle concurrent access**
|
||||
No locking or atomicity guarantees.
|
||||
|
||||
- **`Test.SaveTest` does not validate XML output**
|
||||
Assumes `WriteXml` succeeds; no validation of XML well-formedness.
|
||||
|
||||
- **`Test.SaveTest` does not handle `metaData` being malformed XML**
|
||||
Appends raw `metaData` string; if it is invalid XML, the file may be corrupted.
|
||||
|
||||
- **`Test.SaveTest` does not handle `metaData` being null**
|
||||
`String.IsNullOrEmpty(metaData)` is not checked before appending.
|
||||
|
||||
- **`Test.SaveTest` does not handle `metaData` being empty**
|
||||
Appends `writer.NewLine + writer` (empty) + `metaData` (empty), resulting in a blank line.
|
||||
|
||||
- **`Test.SaveTest` does not handle `metaData` containing `</Test>` or `</TestSetup>`**
|
||||
May interfere with `GetMetaDataFromDTSFile` logic.
|
||||
|
||||
- **`Test.SaveTest` does not handle `metaData` being larger than file buffer**
|
||||
May cause out-of-memory issues for very large metadata.
|
||||
|
||||
- **`Test.SaveTest` does not handle `metaData` being encoded differently than UTF-16**
|
||||
Appending non-UTF-16 data may corrupt the file.
|
||||
|
||||
- **`Test.SaveTest` does not handle `metaData` being truncated or incomplete**
|
||||
May leave the file in an inconsistent state.
|
||||
|
||||
- **`Test.SaveTest` does not handle `metaData` being corrupted or malformed**
|
||||
May cause downstream parsing errors.
|
||||
|
||||
- **`Test.SaveTest` does not handle `metaData` being duplicated**
|
||||
May cause duplicate metadata sections.
|
||||
|
||||
- **`Test.SaveTest`
|
||||
@@ -0,0 +1,131 @@
|
||||
---
|
||||
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 channel’s 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 channel’s 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.
|
||||
@@ -0,0 +1,189 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/Test/Module/Channel/IConvertable.cs
|
||||
- Common/DTS.Common.Serialization/Test/Module/Channel/ChannelWithMeta.cs
|
||||
- Common/DTS.Common.Serialization/Test/Module/Channel/DataArray.cs
|
||||
generated_at: "2026-04-16T03:40:40.401644+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "6e59e4819411113f"
|
||||
---
|
||||
|
||||
# Channel
|
||||
|
||||
## Documentation: `DTS.Serialization.Test.Module.Channel` Submodule
|
||||
|
||||
---
|
||||
|
||||
### 1. Purpose
|
||||
|
||||
This module defines core serialization abstractions for channel data within the DTS test data serialization framework. It provides interfaces and classes to represent channel metadata, raw data arrays, and conversion mechanisms between domain-specific objects and a canonical `Channel` representation used for persistence or transmission. The module serves as the foundational layer for serializing and deserializing time-series channel data—including scaling, timing, and unit-conversion metadata—into and from XML.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
#### `IConvertable` Interface
|
||||
*(Nested in `DTS.Serialization.Test.Module.Channel`)*
|
||||
|
||||
- **`Channel ToDtsSerializationTestModuleChannel()`**
|
||||
Converts the implementing object into a canonical `Channel` instance.
|
||||
|
||||
- **`void FromDtsSerializationTestModuleChannel(Channel channel)`**
|
||||
Initializes the implementing object using data from a `Channel` instance.
|
||||
|
||||
> **Note**: This interface is intended to be implemented by domain objects that need to be serialized/deserialized as `Channel` instances. The interface name is intentionally misspelled (`IConvertable` instead of `IConvertible`) per source.
|
||||
|
||||
---
|
||||
|
||||
#### `ChannelWithMeta` Class
|
||||
*(Top-level in `DTS.Serialization`)*
|
||||
|
||||
- **`Channel Channel { get; }`**
|
||||
The canonical channel object to be serialized.
|
||||
|
||||
- **`DataScaler Scaler { get; }`**
|
||||
Scaling metadata associated with the channel.
|
||||
|
||||
- **`double SampleRate { get; }`**
|
||||
Sample rate (in Hz) of the channel.
|
||||
|
||||
- **`double StartTime { get; }`**
|
||||
Start time (in seconds) of the channel’s data.
|
||||
|
||||
- **`ChannelWithMeta(Channel channel, DataScaler scaler, double samplerate, double starttime)`**
|
||||
Constructor initializing all properties.
|
||||
|
||||
- **`static double GetMinStartTime(double start, IList<ChannelWithMeta> channelsWithMeta)`**
|
||||
Computes the earliest *common* start time across all provided channels and the given `start` offset. Uses `Math.Max(start, channelsWithMeta.Min(cwm => cwm.StartTime))`.
|
||||
> **Comment in source**: “Start is a generally a negative value, so to get the value for the start time of the minimum common data set, run Max()”.
|
||||
|
||||
- **`static double GetMinStopTime(double stop, IList<ChannelWithMeta> channelsWithMeta)`**
|
||||
Computes the latest *common* stop time across all channels. Uses:
|
||||
`Math.Min(stop, min(cwm.StartTime + (cwm.Channel.PersistentChannelInfo.Length - 1) / cwm.SampleRate))`,
|
||||
with intermediate casting to `decimal` to mitigate floating-point rounding errors.
|
||||
|
||||
---
|
||||
|
||||
#### `DataArray<DataType>` Class
|
||||
*(Nested in `DTS.Serialization.Test.Module.Channel`)*
|
||||
|
||||
- **`DataType[] Values { get; set; }`**
|
||||
Underlying array of data values. Returns an empty array if uninitialized or null.
|
||||
|
||||
- **`double ScaleFactorMv { get; set; }`**
|
||||
ADC-to-millivolt scaling factor.
|
||||
|
||||
- **`double MvPerEu { get; set; }`**
|
||||
Sensitivity: millivolts per engineering unit.
|
||||
|
||||
- **`double ScaleFactorEU { get; set; }`**
|
||||
EU scaling factor (unused in current XML schema per tags).
|
||||
|
||||
- **`bool UseEUScaleFactors { get; set; }`**
|
||||
Flag indicating whether EU scale factors should be applied.
|
||||
|
||||
- **`short DataZeroLevel { get; set; }`**
|
||||
Zero-level offset for ADC data.
|
||||
|
||||
- **`double UnitConversion { get; set; }`**
|
||||
Unit conversion multiplier (default `1.0`).
|
||||
|
||||
- **`double Multiplier { get; set; }`**
|
||||
General-purpose multiplier (default `1.0`).
|
||||
|
||||
- **`double UserOffsetEU { get; set; }`**
|
||||
User-defined offset in engineering units (default `0.0`).
|
||||
|
||||
- **`DataArray()`**
|
||||
Default constructor.
|
||||
|
||||
- **`DataArray(DataType[] values)`**
|
||||
Constructor initializing `Values` with the provided array.
|
||||
|
||||
- **Implicit operator `List<DataType> → DataArray<DataType>`**
|
||||
Converts a `List<DataType>` to `DataArray<DataType>`.
|
||||
|
||||
- **Implicit operator `DataArray<DataType> → List<DataType>`**
|
||||
Converts `DataArray<DataType>` to `List<DataType>`.
|
||||
|
||||
- **`void WriteXml(XmlWriter writer)`**
|
||||
Serializes the instance to XML with the following structure:
|
||||
```xml
|
||||
<Data Length="N" Type="System.Double" ScaleFactorMv="..." SensitivityMvEu="...">
|
||||
<Datum Value="..." />
|
||||
...
|
||||
</Data>
|
||||
```
|
||||
Includes attributes for `Length`, `Type`, `ScaleFactorMv`, and `SensitivityMvEu`. Each datum is serialized as `<Datum Value="..."/>`.
|
||||
|
||||
- **`void ReadXml(XmlReader reader)`**
|
||||
Deserializes XML into the instance. Requires:
|
||||
- `DataType` to have a public static `Parse(string)` method.
|
||||
- `DataType` to be constructible via `Activator.CreateInstance`.
|
||||
- XML to contain `Length`, `Type`, `ScaleFactorMv`, and `SensitivityMvEu` attributes.
|
||||
|
||||
- **`XmlSchema GetSchema()`**
|
||||
Always returns `null`. Per comment: *“This method is never invoked during XML object serialization.”*
|
||||
|
||||
- **`bool Equals(object obj)`**
|
||||
Memberwise equality test: compares `ScaleFactorMv`, `MvPerEu`, `Values.Length`, and element-wise `Values` equality.
|
||||
|
||||
- **`int GetHashCode()`**
|
||||
Returns base hash code (no custom hashing implemented).
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
|
||||
- **`DataArray<DataType>`**
|
||||
- `Values` is never `null` when accessed (returns empty array if uninitialized).
|
||||
- XML serialization/deserialization requires `DataType` to implement `Parse(string)` and be instantiable via `Activator.CreateInstance`.
|
||||
- `ScaleFactorMv` and `MvPerEu` are always serialized/deserialized as XML attributes (not child elements).
|
||||
- `DataZeroLevel`, `UseEUScaleFactors`, `UnitConversion`, `Multiplier`, `UserOffsetEU` are *not* serialized in XML (no corresponding XML tags), though they are properties.
|
||||
|
||||
- **`ChannelWithMeta`**
|
||||
- `GetMinStartTime` and `GetMinStopTime` assume `StartTime` and `SampleRate` are non-negative and consistent across channels.
|
||||
- `GetMinStopTime` uses `decimal` arithmetic internally to avoid floating-point rounding artifacts.
|
||||
|
||||
- **`IConvertable`**
|
||||
- Implementers must ensure `FromDtsSerializationTestModuleChannel` fully initializes the object from the `Channel` argument.
|
||||
- `ToDtsSerializationTestModuleChannel` must produce a fully populated `Channel` instance.
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
|
||||
#### Imports/Usings
|
||||
- `System`, `System.Collections.Generic`, `System.Linq` → used in `ChannelWithMeta`.
|
||||
- `DTS.Common.DAS.Concepts` → provides `DataScaler` type (used in `ChannelWithMeta`).
|
||||
- `System.Xml`, `System.Xml.Schema`, `System.Xml.Serialization` → used in `DataArray<DataType>`.
|
||||
- `DTS.Common.Utilities`, `DTS.Common.Utilities.DotNetProgrammingConstructs` → provides `Exceptional` base class and `Property<T>` wrapper (used in `DataArray<DataType>`).
|
||||
|
||||
#### Known Dependencies
|
||||
- `DTS.Serialization.Test.Module.Channel` (itself) — `ChannelWithMeta` references `Channel` and `PersistentChannelInfo.Length`.
|
||||
- `DataScaler` — assumed to be defined in `DTS.Common.DAS.Concepts`.
|
||||
- `Property<T>` — internal wrapper used for observable/validated properties in `DataArray<T>`.
|
||||
|
||||
#### Dependents (Inferred)
|
||||
- Serialization/deserialization pipelines (e.g., XML writers/readers) that consume `DataArray<T>`.
|
||||
- Higher-level serialization modules that use `IConvertable` to bridge domain objects and `Channel`.
|
||||
- `ChannelWithMeta` consumers (e.g., file writers) that need to align multiple channels in time.
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
|
||||
- **Typo in interface name**: `IConvertable` (not `IConvertible`) — likely historical.
|
||||
- **`DataArray<T>` XML schema is incomplete**: Only `ScaleFactorMv` and `MvPerEu` are serialized; other properties (`ScaleFactorEU`, `DataZeroLevel`, etc.) are ignored in XML.
|
||||
- **`GetSchema()` always returns `null`**: This is intentional per comment, but may confuse developers expecting a schema for validation.
|
||||
- **Rounding mitigation in `GetMinStopTime`**: Uses `decimal` cast to avoid floating-point artifacts (e.g., `4.999999999999995` vs `5.0`), but this may be fragile if `StartTime` or `SampleRate` are very large/small.
|
||||
- **`DataArray<T>` requires `Parse(string)`**: If `DataType` lacks a static `Parse(string)` method, `ReadXml` throws an exception.
|
||||
- **`Values` property returns empty array if null**: This avoids null-reference exceptions but may mask uninitialized state.
|
||||
- **Implicit conversions are one-way in practice**: While both implicit operators exist, `DataArray<T>` is not a `List<T>`—conversions copy data, not reference.
|
||||
|
||||
> **None identified from source alone** beyond the above.
|
||||
|
||||
---
|
||||
|
||||
*Documentation generated from provided source files. No external assumptions or API speculation applied.*
|
||||
@@ -0,0 +1,208 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/TestSetup/ExtraProperty.cs
|
||||
- Common/DTS.Common.Serialization/TestSetup/Sensor.cs
|
||||
- Common/DTS.Common.Serialization/TestSetup/TestSetup.cs
|
||||
generated_at: "2026-04-16T03:38:27.625300+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "94471ae1594e14ef"
|
||||
---
|
||||
|
||||
# Documentation: `DTS.Serialization.TestSetup` Module
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module defines core data structures used to serialize and deserialize test setup configurations in the DTS (Dynamic Test System) platform. It provides strongly-typed, property-backed classes (`TestSetup`, `Sensor`, `ExtraProperty`) that model metadata about a test run—including laboratory and customer information, test parameters, associated sensors, graphs, and upload settings. These classes are designed to support XML serialization (evidenced by `[Serializable]` and `[XmlIgnore]` attributes) and are part of a larger serialization framework leveraging `DTS.Common.Utilities.DotNetProgrammingConstructs.Property<T>` for change tracking and metadata management. The module serves as the foundational schema for persisting and restoring test configurations across sessions.
|
||||
|
||||
---
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
All classes reside in the `DTS.Serialization` namespace and inherit from `Exceptional`.
|
||||
|
||||
### `TestSetup` (partial class, `[Serializable]`)
|
||||
|
||||
- **`TestSetup()`**
|
||||
Default constructor. Initializes all backing `Property<T>` fields to default values (e.g., `null` for strings, `0` for `Int32`, `CalibrationBehaviors.NonLinearIfAvailable`, empty lists, `"2.0.0.0"` for `Version`, `false` for `Upload`/`UploadExportsOnly`, `""` for `UploadFolder`).
|
||||
**Note**: Several fields are initialized redundantly (e.g., `_dateOfTheTest` is assigned `null` twice), but this is harmless.
|
||||
|
||||
- **`bool Upload`**
|
||||
Indicates whether the test setup was configured to upload when run. Default: `false`.
|
||||
|
||||
- **`string UploadFolder`**
|
||||
Stores the simple upload folder value set in the UI. May be overridden by an INI file at runtime. Default: `""`.
|
||||
|
||||
- **`bool UploadExportsOnly`**
|
||||
Indicates whether only exported files should be uploaded. Default: `false`.
|
||||
|
||||
- **`string ISFFile`**
|
||||
Stores the path or name of the ISF (Instrument Setup File) associated with the test. Default: `""`.
|
||||
|
||||
- **`string DateOfTheTest`**
|
||||
Date of the test as a string. Default: `null`.
|
||||
|
||||
- **`string Description`**
|
||||
Free-text description of the test. Default: `null`.
|
||||
|
||||
- **`CalibrationBehaviors CalibrationBehavior`**
|
||||
Calibration behavior setting. Default: `CalibrationBehaviors.NonLinearIfAvailable`.
|
||||
|
||||
- **`string ExportFolder`**
|
||||
Folder path for exported data. Default: `null`.
|
||||
|
||||
- **`int ExportTypes`**
|
||||
Bitmask or enum value indicating export formats. Default: `0`.
|
||||
|
||||
- **`List<Graph> Graphs`**
|
||||
List of multi-channel graphs defined in the test. Default: new empty list.
|
||||
|
||||
- **`List<Sensor> Sensors`**
|
||||
List of sensors used in the test. Default: new empty list.
|
||||
|
||||
- **`List<ExtraProperty> ExtraProperties`**
|
||||
List of arbitrary key-value metadata pairs. Default: new empty list.
|
||||
|
||||
- **`List<TestObject> TestObjects`**
|
||||
List of test objects involved. *(Note: `TestObject` type not defined in provided sources.)*
|
||||
Default: new empty list.
|
||||
|
||||
- **`List<Graph.Channel> Channels`**
|
||||
Placeholder for all graph channels (XML-ignored). Initialized as empty list.
|
||||
|
||||
- **`List<Graph> SingleChannelGraphs`**
|
||||
Placeholder for single-channel graphs (XML-ignored). Initialized as empty list.
|
||||
|
||||
- **`IDictionary<Guid, Graph> SortedGraphs`**
|
||||
Sorted dictionary of graphs (XML-ignored), populated by `SortGraphs()`.
|
||||
|
||||
- **`void SortGraphs()`**
|
||||
Clears `SortedGraphs`, then populates it with entries from `Graphs` (multi-channel) in order, followed by entries from `SingleChannelGraphs` sorted by `AbsoluteDisplayOrder` of their first channel.
|
||||
|
||||
- **`string LabName`, `LaboratoryName`, `LaboratoryContactName`, `LaboratoryContactPhone`, `LaboratoryContactFax`, `LaboratoryContactEmail`, `LaboratoryTestReferenceNumber`, `LaboratoryProjectReferenceNumber`**
|
||||
Laboratory-related metadata fields. Most default to `null`.
|
||||
**`LaboratoryProjectReferenceNumber`** has a custom getter: returns `""` if `_laboratoryProjectReferenceNumber.IsValueInitialized` is `false`, otherwise returns the value.
|
||||
|
||||
- **`string CustName`, `CustomerName`, `CustomerTestReferenceNumber`, `CustomerProjectReferenceNumber`, `CustomerOrderNumber`, `CustomerCostUnit`**
|
||||
Customer-related metadata fields. All default to `null`.
|
||||
|
||||
- **`string TEName`, `TestEngineerName`, `TestEngineerPhone`, `TestEngineerFax`, `TestEngineerEmail`**
|
||||
Test engineer contact fields.
|
||||
**`TEName`** has a custom getter: returns `""` if `_teName.IsValueInitialized` is `false`, otherwise returns the value.
|
||||
|
||||
- **`string Name`**
|
||||
Name of the test setup. Default: `null`.
|
||||
|
||||
- **`string NumberOfTestObjects`, `NumberOfMedia`**
|
||||
String representations of counts. Default: `null`.
|
||||
|
||||
- **`string ReferenceTemperature`, `Regulation`, `RelativeAirHumidity`, `Subtype`, `TestComment`, `TypeOfTheTest`, `Timestamp`**
|
||||
Various test parameters. All default to `null`.
|
||||
|
||||
- **`virtual string Version`**
|
||||
Version of the `TestSetup` schema. Default: `"2.0.0.0"` (set in constructor). Overridable in derived classes.
|
||||
|
||||
---
|
||||
|
||||
### `TestSetup.Sensor` (nested partial class)
|
||||
|
||||
- **`Sensor()`**
|
||||
Default constructor. Initializes all string properties to `null`, except `Version`, which is set to `"1.0.0.0"`.
|
||||
|
||||
- **`string FilterClass`**
|
||||
Filter class name. Default: `null`.
|
||||
|
||||
- **`string Name`**
|
||||
Sensor name. Default: `null`.
|
||||
|
||||
- **`string Polarity`**
|
||||
Polarity setting (e.g., “Positive”, “Negative”). Default: `null`.
|
||||
|
||||
- **`string Position`**
|
||||
Physical or logical position of the sensor. Default: `null`.
|
||||
|
||||
- **`string Range`**
|
||||
Measurement range of the sensor. Default: `null`.
|
||||
|
||||
- **`string Version`**
|
||||
Schema version for this sensor definition. Default: `"1.0.0.0"`.
|
||||
|
||||
---
|
||||
|
||||
### `TestSetup.ExtraProperty` (nested partial class)
|
||||
|
||||
- **`ExtraProperty()`**
|
||||
Default constructor. Sets `Key` and `Value` to `null`, `Version` to `"1.0.0.0"`.
|
||||
|
||||
- **`ExtraProperty(string key, string value)`**
|
||||
Constructor that initializes `Key` and `Value` to the provided arguments.
|
||||
|
||||
- **`string Key`**
|
||||
Key/name of the extra property. Default: `null`.
|
||||
|
||||
- **`string Value`**
|
||||
Value of the extra property. Default: `null`.
|
||||
|
||||
- **`string Version`**
|
||||
Schema version for this property. Default: `"1.0.0.0"`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- All `Property<T>` fields are initialized with a unique metadata key (e.g., `typeof(TestSetup).Namespace + ".TestSetup.Upload"`) and default value.
|
||||
- The `Version` property of `TestSetup` is initialized to `"2.0.0.0"` in the constructor and is marked `virtual`, implying extensibility.
|
||||
- The `Version` properties of `Sensor` and `ExtraProperty` are initialized to `"1.0.0.0"`.
|
||||
- `UploadFolder` and `ISFFile` default to `""` (empty string), not `null`.
|
||||
- `ExportTypes` defaults to `0` (i.e., no export formats selected).
|
||||
- `CalibrationBehavior` defaults to `CalibrationBehaviors.NonLinearIfAvailable`.
|
||||
- `Graphs`, `Sensors`, `ExtraProperties`, and `TestObjects` default to new empty lists (not `null`).
|
||||
- `Channels`, `SingleChannelGraphs`, and `SortedGraphs` are XML-ignored and used only at runtime.
|
||||
- `SortGraphs()` enforces ordering: multi-channel `Graphs` first (in original list order), then `SingleChannelGraphs` sorted by `AbsoluteDisplayOrder` of their first channel.
|
||||
- `TEName` and `LaboratoryProjectReferenceNumber` have non-standard getters: they return `""` if the underlying `Property<T>.IsValueInitialized` is `false`, otherwise return the stored value.
|
||||
|
||||
---
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### Internal Dependencies (from source):
|
||||
- `DTS.Common.Utilities` — Provides base types (`Exceptional`, `Property<T>`).
|
||||
- `DTS.Common.Utilities.DotNetProgrammingConstructs` — Contains `Property<T>` implementation.
|
||||
- `DTS.Common.Enums.Sensors` — Defines `CalibrationBehaviors` enum (used in `TestSetup.CalibrationBehavior`).
|
||||
- `System.Collections.Generic` — For `List<T>` and `IDictionary<TKey, TValue>`.
|
||||
- `System.Xml.Serialization` — Used for `[Serializable]` and `[XmlIgnore]` attributes.
|
||||
|
||||
### External Dependencies (inferred):
|
||||
- `Graph` class — Referenced in `TestSetup.Graphs`, `SingleChannelGraphs`, `Channels`, and `SortedGraphs`. Not defined in provided sources, but its nested `Channel` class and `Identifier` and `FirstTestChannel` properties are used.
|
||||
- `TestObject` class — Referenced in `TestSetup.TestObjects`. Not defined in provided sources.
|
||||
- `GraphDisplayOrderComparer` — A private method in `TestSetup` that compares `Graph` instances by `AbsoluteDisplayOrder` of their first channel.
|
||||
|
||||
---
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **Redundant field initialization**: In `TestSetup()`, `_dateOfTheTest.Value = null` appears twice. Likely a copy-paste artifact, but harmless.
|
||||
- **Inconsistent null vs. empty string defaults**:
|
||||
- `UploadFolder`, `ISFFile` → `""`
|
||||
- `ExportFolder`, `DateOfTheTest`, `Description`, etc. → `null`
|
||||
This may cause confusion when checking for presence (e.g., `string.IsNullOrEmpty()` vs. `null` checks).
|
||||
- **Non-standard getters for optional fields**:
|
||||
`TEName` and `LaboratoryProjectReferenceNumber` return `""` when uninitialized, while other string properties return `null`. This breaks consistency and may lead to bugs if consumers assume uniform nullability.
|
||||
- **`IsValueInitialized` usage is undocumented in `Property<T>`**:
|
||||
The behavior of `IsValueInitialized` is not defined in the source; its semantics (e.g., whether it tracks explicit `null` assignments) are unknown.
|
||||
- **`Version` is `virtual` in `TestSetup` but not in nested classes**:
|
||||
`Sensor.Version` and `ExtraProperty.Version` are not `virtual`, suggesting they are not intended for override, while `TestSetup.Version` is. This may indicate a versioning strategy where only top-level objects evolve schema.
|
||||
- **`ExtraProperties` and `Sensors` lists are mutable but not defensively copied**:
|
||||
Setting `TestSetup.Sensors = null` or `TestSetup.Sensors = new List<Sensor>()` is allowed, but no validation prevents null or duplicate entries.
|
||||
- **`SortGraphs()` mutates `SortedGraphs` but does not validate inputs**:
|
||||
If `Graph.Identifier` is not unique, `SortedGraphs.Add()` will throw an `ArgumentException`.
|
||||
- **`GraphDisplayOrderComparer` may throw `NullReferenceException`**:
|
||||
If `a.FirstTestChannel` or `b.FirstTestChannel` is `null`, the comparison will fail. No null checks are present.
|
||||
- **`[Serializable]` on `TestSetup` but no `ISerializable` implementation**:
|
||||
Relies on default .NET serialization; may break across assembly version changes if field names or types change.
|
||||
|
||||
---
|
||||
|
||||
*Documentation generated from provided source files. No external assumptions or behaviors were inferred beyond what is strictly observable.*
|
||||
@@ -0,0 +1,154 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/TestSetup/Graph/Graph.cs
|
||||
- Common/DTS.Common.Serialization/TestSetup/Graph/Channel.cs
|
||||
generated_at: "2026-04-16T03:41:07.285794+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "54ff68752851044a"
|
||||
---
|
||||
|
||||
# Graph
|
||||
|
||||
## Documentation: `DTS.Serialization.Graph` and `DTS.Serialization.Graph.Channel`
|
||||
|
||||
---
|
||||
|
||||
### 1. **Purpose**
|
||||
|
||||
This module defines core serialization-friendly data structures (`Graph` and `Channel`) used to represent test setup configurations in the DTS (Dynamic Test System) framework. The `Graph` class encapsulates a test configuration as a named, versioned container of one or more `Channel` instances, each representing a logical test channel tied to either a live `Test.Module.Channel` object or a placeholder for deserialization scenarios. These classes are designed for XML serialization (evidenced by use of `XmlIgnoreAttribute`) and serve as a lightweight, serializable abstraction layer over the richer, runtime `Test.Module` domain model—enabling persistence, transmission, or reconstruction of test setups without coupling to the full test execution engine.
|
||||
|
||||
---
|
||||
|
||||
### 2. **Public Interface**
|
||||
|
||||
#### `DTS.Serialization.TestSetup.Graph`
|
||||
|
||||
- **`Graph()`**
|
||||
Default constructor. Initializes `_Version.Value` to `"1.0.0.0"`, sets `_Name.Value` to `null`, and assigns a new `Guid` to `Identifier`.
|
||||
|
||||
- **`void UnSet()`**
|
||||
No-op method (empty implementation). Purpose unclear from source.
|
||||
|
||||
- **`List<Channel> Channels { get; set; }`**
|
||||
Gets or sets the list of channels in this graph. Initialized to an empty list by default.
|
||||
|
||||
- **`string Name { get; set; }`**
|
||||
Gets or sets the graph’s logical name. Defaults to `""`.
|
||||
|
||||
- **`string HardwareChannelName { get; set; }`**
|
||||
Gets or sets a hardware-specific channel name (e.g., physical port label). Defaults to `""`.
|
||||
|
||||
- **`string DisplayName { get; }`**
|
||||
Computed property: concatenates `Name` and `HardwareChannelName` with an underscore (`Name + "_" + HardwareChannelName`). May yield `"_"` if both are empty.
|
||||
|
||||
- **`string Version { get; set; }`**
|
||||
Gets or sets the graph version string. *Note:* Constructor sets `_Version.Value = "1.0.0.0"`, but the backing field `_Version` is initialized with `""` as default—this is overwritten in the constructor.
|
||||
|
||||
- **`override string ToString()`**
|
||||
Returns `Name`.
|
||||
|
||||
- **`bool IsSingleChannelGraph { get; }`**
|
||||
Returns `true` if `Channels` is non-null and contains exactly one element.
|
||||
|
||||
- **`Channel FirstChannel { get; }`**
|
||||
Returns the first element in `Channels`. **Unsafe**: throws `IndexOutOfRangeException` if `Channels` is null or empty.
|
||||
|
||||
- **`Test.Module.Channel FirstTestChannel { get; }`**
|
||||
Returns `FirstChannel.TestChannel`. **Unsafe**: throws `IndexOutOfRangeException` if `Channels` is null/empty, or `NullReferenceException` if `FirstChannel.TestChannel` is null.
|
||||
|
||||
- **`Guid Identifier { get; private set; }`**
|
||||
Unique identifier for the graph instance. Set only in constructor via `Guid.NewGuid()`.
|
||||
|
||||
#### `DTS.Serialization.TestSetup.Graph.Channel`
|
||||
|
||||
- **`Channel()`** *(private)*
|
||||
Internal constructor. Sets `ChannelId = "Not Set"`. Not used externally.
|
||||
|
||||
- **`Channel(Test.Module.Channel channel)`**
|
||||
Constructor for wrapping an existing runtime `Test.Module.Channel`. Populates:
|
||||
- `ParentTestModule` = `channel.ParentModule`
|
||||
- `TestChannel` = `channel`
|
||||
- `ChannelId` = `channel.ChannelId`
|
||||
- `ChannelGroupName` = `channel.ChannelGroupName`
|
||||
*Note:* A `TODO` comment indicates intent to use a unique key (e.g., `Identifier`) instead of `HardwareChannelName`—but this is not implemented.
|
||||
|
||||
- **`Channel(string channelId)`**
|
||||
Constructor for placeholder channel (e.g., deserialization). Sets `ParentTestModule = null`, `TestChannel = null`, and `ChannelId = channelId`.
|
||||
|
||||
- **`Channel(long groupChannelId)`**
|
||||
Constructor for placeholder channel from numeric ID. Sets `ParentTestModule = null`, `TestChannel = null`, and `ChannelId = groupChannelId.ToString()`.
|
||||
|
||||
- **`override string ToString()`**
|
||||
Returns `TestChannel.ToString()` if `TestChannel` is non-null; otherwise `"Not Set"`.
|
||||
|
||||
- **`string ChannelId { get; set; }`**
|
||||
Logical channel identifier (e.g., `"TestObjectSerial_ChannelType_ChannelId"`). Used as a unique key *in practice*, though not enforced.
|
||||
|
||||
- **`string ChannelGroupName { get; set; }`**
|
||||
Group name for the channel (e.g., `"Axial"`, `"Radial"`).
|
||||
|
||||
- **`string Name { get; }`**
|
||||
Returns `TestChannel.ChannelDescriptionString` if `TestChannel` is non-null; otherwise `"Not Set"`.
|
||||
|
||||
- **`string SensorName { get; }`**
|
||||
Returns `TestChannel.ChannelDescriptionString.ToString()` if `TestChannel` is non-null; otherwise `"Not Set"`.
|
||||
*Note:* Redundant with `Name`; likely legacy or for XML serialization compatibility.
|
||||
|
||||
- **`string AxisUnit { get; }`**
|
||||
Returns engineering units (`AnalogInputChannel.EngineeringUnits`) if `TestChannel` is an `AnalogInputChannel`; otherwise `"EU"`.
|
||||
|
||||
- **`string SerialNumber { get; }`**
|
||||
Returns `ParentTestModule.SerialNumber` if `ParentTestModule` is non-null; otherwise `"Not Set"`.
|
||||
|
||||
- **`Test.Module ParentTestModule;`**
|
||||
Public field referencing the parent test module (e.g., sensor or DAQ device). May be `null` for placeholder channels.
|
||||
|
||||
- **`Test.Module.Channel TestChannel;`**
|
||||
Public field referencing the underlying runtime channel object. May be `null` for placeholder channels.
|
||||
|
||||
---
|
||||
|
||||
### 3. **Invariants**
|
||||
|
||||
- **`Graph.Identifier`** is assigned exactly once during construction and never modified afterward.
|
||||
- **`Graph.Channels`** is never `null` after construction (initialized to `new List<Channel>()` in `_Channels`).
|
||||
- **`Graph.Version`** is initialized to `"1.0.0.0"` in the constructor, overriding the default `""` in `_Version`.
|
||||
- **`Channel.ChannelId`** is always set (non-null) and used as a logical identifier, though uniqueness is not enforced by the class.
|
||||
- **`Graph.DisplayName`** may be malformed (e.g., `"_"`, `"_" + HardwareChannelName`) if `Name` is empty or whitespace.
|
||||
- **`Graph.FirstChannel`** and **`Graph.FirstTestChannel`** assume `Channels.Count >= 1`; no bounds checking is performed.
|
||||
|
||||
---
|
||||
|
||||
### 4. **Dependencies**
|
||||
|
||||
- **Internal Dependencies**:
|
||||
- `DTS.Common.Utilities` (namespace)
|
||||
- `DTS.Common.Utilities.DotNetProgrammingConstructs` (for `Property<T>` wrapper)
|
||||
- `System`, `System.Collections.Generic`, `System.Xml.Serialization`
|
||||
|
||||
- **External Dependencies**:
|
||||
- `Test.Module` (namespace): referenced via `Test.Module.Channel`, `Test.Module.ParentTestModule`, `Test.Module.AnalogInputChannel`, and `Test.Module.Channel.ChannelDescriptionString`.
|
||||
*This implies a hard dependency on the `Test.Module` assembly (likely `DTS.TestModule.dll` or similar).*
|
||||
- `Exceptional`: Base class for both `Graph` and `Channel` (inherited from `TestSetup.Exceptional`).
|
||||
|
||||
- **Depended Upon By**:
|
||||
- Serialization infrastructure (e.g., XML serializers, given `[XmlIgnore]` usage).
|
||||
- Test setup persistence layers (e.g., saving/loading `.xml` test configurations).
|
||||
- UI or tooling that consumes serialized test setups.
|
||||
|
||||
---
|
||||
|
||||
### 5. **Gotchas**
|
||||
|
||||
- **`Graph.FirstChannel` and `Graph.FirstTestChannel` are unsafe**: No null/empty checks—accessing them on an empty `Channels` list will throw `IndexOutOfRangeException`.
|
||||
- **`DisplayName` may produce misleading output**: Concatenation of `Name` and `HardwareChannelName` without trimming or validation can yield `"_"` or `"Name_"`.
|
||||
- **`Channel` constructors are inconsistent in initialization**:
|
||||
- `Channel(Test.Module.Channel)` populates `ParentTestModule` and `TestChannel`.
|
||||
- `Channel(string)` and `Channel(long)` leave them `null`.
|
||||
Code must check for null `TestChannel`/`ParentTestModule` before accessing derived properties (`Name`, `SerialNumber`, etc.).
|
||||
- **`SensorName` duplicates `Name` logic**: Both use `TestChannel.ChannelDescriptionString`, but `SensorName` calls `.ToString()` explicitly—likely redundant or legacy.
|
||||
- **`HardwareChannelName` is unused in `Channel` constructor**: The `TODO` comment suggests `Identifier` should be set from `HardwareChannelName`, but this is not implemented. `Identifier` remains `Guid.NewGuid()` (graph-level), while `Channel` has no `Identifier` field.
|
||||
- **`Channel` has no `Identifier` field**: Unlike `Graph`, `Channel` lacks a unique ID—relying on `ChannelId` (a string) as a de facto key, but this is not enforced or validated.
|
||||
- **`UnSet()` is a no-op**: Its purpose is unclear; may be a placeholder for future cleanup or legacy pattern.
|
||||
- **`Property<T>` behavior**: The `Property<T>` wrapper (from `DotNetProgrammingConstructs`) likely handles change notifications or serialization metadata, but its exact semantics (e.g., null handling, validation) are not visible here. Default values (`""`, `new List<Channel>()`) are set in field initializers, but constructor overrides (e.g., `Version = "1.0.0.0"`) may conflict with expectations.
|
||||
@@ -0,0 +1,192 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/TestSetup/TestObject/Channel.cs
|
||||
- Common/DTS.Common.Serialization/TestSetup/TestObject/DASHardware.cs
|
||||
- Common/DTS.Common.Serialization/TestSetup/TestObject/DASHardware.DASChannel.cs
|
||||
- Common/DTS.Common.Serialization/TestSetup/TestObject/TestObject.cs
|
||||
generated_at: "2026-04-16T03:41:14.998508+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "5d62833ecdd15a59"
|
||||
---
|
||||
|
||||
# Documentation: `TestObject` Serialization Model
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module defines a set of strongly-typed, serializable data structures used to represent test setup metadata in the DTS (Dynamic Testing System) serialization framework. Specifically, it provides models for `TestObject`, `DASHardware` (Data Acquisition System hardware), and associated channel types (`TOChannel`, `DASChannel`). These classes encapsulate metadata about physical test objects (e.g., impact hammers, barriers), associated hardware (e.g., DAS units), and their channels (sensors), enabling structured storage, retrieval, and exchange of test configuration data. The classes are designed to support versioning, naming, and descriptive properties while leveraging a custom `Property<T>` wrapper for internal state management.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
All classes are `partial` and nested inside `DTS.Serialization.TestSetup.TestObject`. They inherit from `Exceptional` (not shown, but assumed to provide exception-handling or logging infrastructure).
|
||||
|
||||
### `TestObject` Class
|
||||
|
||||
- **`TestObject()`**
|
||||
Default constructor initializing all properties to `null` (except `Version`, initialized to `"1.0.0.0"` and list properties to empty lists).
|
||||
|
||||
- **`string NameOfTestObject { get; set; }`**
|
||||
Human-readable name of the test object (e.g., `"Hammer A"`).
|
||||
|
||||
- **`string SerialNumber { get; set; }`**
|
||||
Manufacturer’s serial number of the test object.
|
||||
|
||||
- **`string CodeOfTestObject { get; set; }`**
|
||||
Internal or standardized code identifying the test object type.
|
||||
|
||||
- **`string ClassOfTestObject { get; set; }`**
|
||||
Classification of the test object (e.g., `"Hammer"`, `"Barrier"`).
|
||||
|
||||
- **`string Location { get; set; }`**
|
||||
Physical or logical location of the test object.
|
||||
|
||||
- **`string Version { get; set; }`**
|
||||
Version string of the test object definition (default: `"1.0.0.0"`).
|
||||
|
||||
- **`List<TOChannel> Channels { get; set; }`**
|
||||
List of `TOChannel` instances associated with this test object.
|
||||
|
||||
- **`List<DASHardware> DASHardwares { get; set; }`**
|
||||
List of `DASHardware` instances linked to this test object.
|
||||
|
||||
- **`string BarrierHeight { get; set; }`**
|
||||
Height of a barrier test object (if applicable).
|
||||
|
||||
- **`string BarrierWidth { get; set; }`**
|
||||
Width of a barrier test object.
|
||||
|
||||
- **`string ImpactSideTestObject { get; set; }`**
|
||||
Side of the test object used for impact (e.g., `"Top"`, `"Bottom"`).
|
||||
|
||||
- **`string DriverPositionObject { get; set; }`**
|
||||
Position of the driver relative to the test object.
|
||||
|
||||
- **`string MassOfTestObject { get; set; }`**
|
||||
Mass of the test object (string representation, e.g., `"5.2 kg"`).
|
||||
|
||||
- **`string Velocity { get; set; }`**
|
||||
Velocity associated with the test object (e.g., impact velocity).
|
||||
|
||||
- **`string VelocityMeasurementUnit { get; set; }`**
|
||||
Unit of measurement for `Velocity` (e.g., `"m/s"`).
|
||||
|
||||
- **`string Offset { get; set; }`**
|
||||
Offset value (e.g., zero offset in measurement).
|
||||
|
||||
- **`string OriginX/Y/Z { get; set; }`**
|
||||
3D coordinate origin (string values, likely in meters).
|
||||
|
||||
- **`string ReferenceSystem { get; set; }`**
|
||||
Coordinate reference system (e.g., `"WGS84"`, `"Local"`).
|
||||
|
||||
- **`string RefNumberOfTestObject { get; set; }`**
|
||||
Reference number or ID assigned to the test object.
|
||||
|
||||
- **`string NumberOfLoadCells { get; set; }`**
|
||||
Number of load cells used in the test.
|
||||
|
||||
- **`string TargetSampleRate { get; set; }`**
|
||||
Desired sample rate for data acquisition.
|
||||
|
||||
- **`string ExcitationWarmupMS { get; set; }`**
|
||||
Warm-up time before excitation (in milliseconds).
|
||||
|
||||
- **`string Comment1/2/3 { get; set; }`**
|
||||
Free-text comment fields.
|
||||
|
||||
- **`string YawAngle { get; set; }`**
|
||||
Angular orientation (e.g., yaw in degrees).
|
||||
|
||||
- **`List<ExtraProperty> ExtraProperties { get; set; }`**
|
||||
List of arbitrary key-value metadata (type `ExtraProperty` not defined here; assumed to be defined elsewhere).
|
||||
|
||||
> **Note**: The `TypeOfTestObject` property is commented out and not part of the public interface.
|
||||
|
||||
### `TOChannel` Class
|
||||
|
||||
- **`TOChannel()`**
|
||||
Default constructor initializing `_version` to `"1.0.0.0"`; other fields to `null`.
|
||||
|
||||
- **`string Name { get; set; }`**
|
||||
Name of the channel (e.g., `"Channel_1"`).
|
||||
|
||||
- **`string SensorName { get; set; }`**
|
||||
Name of the sensor associated with this channel.
|
||||
|
||||
- **`string Version { get; set; }`**
|
||||
Version of the channel definition (default: `"1.0.0.0"`).
|
||||
|
||||
### `DASHardware` Class
|
||||
|
||||
- **`DASHardware()`**
|
||||
Default constructor initializing `_version` to `"1.0.0.0"`; other fields to `null`.
|
||||
|
||||
- **`List<DASChannel> DASChannels { get; set; }`**
|
||||
List of `DASChannel` instances attached to this DAS hardware.
|
||||
|
||||
- **`string SampleRate { get; set; }`**
|
||||
Sample rate configured for this DAS hardware (e.g., `"2000 Hz"`).
|
||||
|
||||
- **`string SerialNumber { get; set; }`**
|
||||
Serial number of the DAS hardware unit.
|
||||
|
||||
- **`string Version { get; set; }`**
|
||||
Version of the DAS hardware definition (default: `"1.0.0.0"`).
|
||||
|
||||
### `DASHardware.DASChannel` Class
|
||||
|
||||
- **`DASChannel()`**
|
||||
Default constructor initializing `_version` to `"1.0.0.0"`; other fields to `null`.
|
||||
|
||||
- **`string Name { get; set; }`**
|
||||
Name of the DAS channel (e.g., `"DAS_Ch1"`).
|
||||
|
||||
- **`string SensorName { get; set; }`**
|
||||
Name of the physical sensor connected to this channel.
|
||||
|
||||
- **`string SerialNumber { get; set; }`**
|
||||
Serial number of the sensor.
|
||||
|
||||
- **`string Location { get; set; }`**
|
||||
Physical location of the sensor (e.g., `"Top Flange"`).
|
||||
|
||||
- **`string MeasurementUnits { get; set; }`**
|
||||
Units of measurement for this channel (e.g., `"g"`, `"V"`).
|
||||
|
||||
- **`string NumberOfSamples { get; set; }`**
|
||||
Number of samples recorded on this channel.
|
||||
|
||||
- **`string Version { get; set; }`**
|
||||
Version of the DAS channel definition (default: `"1.0.0.0"`).
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **Default `Version`**: All classes (`TestObject`, `TOChannel`, `DASHardware`, `DASChannel`) initialize their `Version` property to `"1.0.0.0"` in the constructor. This is the only guaranteed non-null default value.
|
||||
- **List Properties**: All list properties (`Channels`, `DASHardwares`, `DASChannels`, `ExtraProperties`) are initialized to empty lists (`new List<T>()`) in their respective `Property<T>` declarations. They are never `null` unless explicitly set to `null` via setter.
|
||||
- **String Properties**: All string properties are backed by `Property<string>` initialized with non-null default values (empty string `""`). However, the constructor sets them to `null` *before* the `Property<T>` default is applied, meaning:
|
||||
- Immediately after construction, all string properties are `null`.
|
||||
- The `Property<T>` default (`""`) is only used if the property is never explicitly set.
|
||||
- **Namespace-based Property Keys**: Each `Property<T>` instance uses a key derived from `typeof(...).Namespace + "." + [ClassName].[PropertyName]`. This implies a strict naming convention for property metadata, but the key itself is internal and not exposed via the public API.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
- **Internal Dependencies**:
|
||||
- `DTS.Common.Utilities` and `DTS.Common.Utilities.DotNetProgrammingConstructs` namespaces (likely containing the `Exceptional` base class and `Property<T>` implementation).
|
||||
- `System.Collections.Generic` for `List<T>` usage.
|
||||
- **External Dependencies**:
|
||||
- `ExtraProperty` (used in `TestObject.ExtraProperties`) is referenced but not defined in the provided files. Its definition must exist elsewhere in the codebase.
|
||||
- `DASHardware.DASChannel` is defined in a separate file (`DASHardware.DASChannel.cs`) using `partial` class extension, indicating a split implementation (likely for maintainability or code generation).
|
||||
- **Dependents**:
|
||||
- This module is part of `DTS.Serialization`, implying usage by serialization/deserialization logic (e.g., XML/JSON converters, test setup loaders) not included here.
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **String vs. Typed Values**: All properties are `string`-typed, even for numeric or structured data (e.g., `SampleRate`, `OriginX`, `MassOfTestObject`). Consumers must parse or interpret these values themselves. No validation or type conversion is performed by the model.
|
||||
- **Null vs. Empty String**: While `Property<T>` defaults to `""`, the constructor explicitly sets all string fields to `null`. This means:
|
||||
- A newly constructed object has `null` for all string properties.
|
||||
- An unset property remains `null` (not `""`), which may differ from expectations based on the `Property<T>` default.
|
||||
- **No Validation**: No setters enforce constraints (e.g., `Version` format, non-empty `Name`). Validation must be handled externally.
|
||||
- **Partial Class Fragmentation**: `DASHardware` and `DASChannel` are split across files (`DASHardware.cs` and `DASHardware.DASChannel.cs`). Developers must be aware of both files to see the full class definition.
|
||||
- **Commented-Out Property**: `TypeOfTestObject` is commented out in `TestObject.cs`. Its absence may indicate legacy or deprecated functionality; do not rely on it.
|
||||
- **Ambiguous Units**: Properties like `VelocityMeasurementUnit` and `MeasurementUnits` rely on string values without enforced unit standards (e.g., SI vs. imperial), risking misinterpretation without external documentation.
|
||||
- **No Invariants Enforced on Lists**: While lists are initialized, there is no protection against adding `null` elements (e.g., `testObject.Channels.Add(null)` is allowed).
|
||||
@@ -0,0 +1,179 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common.Serialization/XLSX/Excel.File.cs
|
||||
- Common/DTS.Common.Serialization/XLSX/Excel.File.Writer.cs
|
||||
generated_at: "2026-04-16T03:37:36.193666+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "3504eb010d91451f"
|
||||
---
|
||||
|
||||
# XLSX
|
||||
|
||||
## Documentation: `DTS.Serialization.XLSX.File`
|
||||
|
||||
---
|
||||
|
||||
### 1. Purpose
|
||||
|
||||
This module provides XLSX-specific serialization functionality for `Test` objects, implementing the abstract `Serialization.File` base class and the `IWritable<Test>` interface. Its primary purpose is to export test data (e.g., analog channel measurements) into Excel-compatible `.xlsx` files using the Open XML SDK. Currently, it supports exporting Engineering Units (EU) by default, with optional controls for exporting raw ADC counts (`ExportADC`) and millivolt values (`ExportMV`). The implementation is tightly coupled to the `Test` model and its channel hierarchy, and it supports both raw and filtered data export based on runtime configuration.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
#### `public partial class File : Serialization.File, IWritable<Test>`
|
||||
|
||||
- **`public File()`**
|
||||
Constructor. Initializes the base class with `"XLSX"` as the file type identifier.
|
||||
|
||||
- **`public IWriter<Test> Exporter { get; }`**
|
||||
Returns the singleton `Writer` instance for this `File`. Lazily instantiates a `Writer` on first access using `DefaultEncoding`. Throws an `Exception` (wrapping the inner exception) if instantiation fails.
|
||||
|
||||
- **`public bool ExportADC { set; }`**
|
||||
Sets the `ExportADC` property on the underlying `Writer` instance. Controls whether raw ADC values are exported.
|
||||
|
||||
- **`public bool ExportEU { set; }`**
|
||||
Sets the `ExportEU` property on the underlying `Writer`. Controls whether Engineering Units (EU) are exported (default: `true`).
|
||||
|
||||
- **`public bool ExportMV { set; }`**
|
||||
Sets the `ExportMv` property on the underlying `Writer`. Controls whether millivolt (`mV`) values are exported.
|
||||
|
||||
> **Note**: All three export flags (`ExportADC`, `ExportEU`, `ExportMV`) are *setters only* on `File`. There is no public getter, and the flags are applied only during the `Write(...)` call on the `Writer`.
|
||||
|
||||
---
|
||||
|
||||
#### `public class Writer : Writer<File>, IWriter<Test>`
|
||||
|
||||
- **`internal File WriterParent { get; }`**
|
||||
Reference to the owning `File` instance.
|
||||
|
||||
- **`public bool ExportADC { get; set; }`**
|
||||
Gets/sets whether to export raw ADC values.
|
||||
|
||||
- **`public bool ExportEU { get; set; }`**
|
||||
Gets/sets whether to export Engineering Units.
|
||||
|
||||
- **`public bool ExportMv { get; set; }`**
|
||||
Gets/sets whether to export millivolt values.
|
||||
|
||||
- **`public double Start { get; set; }`**
|
||||
Start time (in seconds) for data slicing.
|
||||
|
||||
- **`public double Stop { get; set; }`**
|
||||
Stop time (in seconds) for data slicing.
|
||||
|
||||
- **`public bool Filtered { get; set; }`**
|
||||
If `true`, applies software filtering (via `SaeJ211Filter`) to EU data before export.
|
||||
|
||||
- **`public void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)`**
|
||||
*Overload 1 (incomplete implementation)* — currently has no body.
|
||||
|
||||
- **`public void Write(string pathname, string id, string dataFolder, Test test, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Test.Module.Channel tmChannel, int channelNumber, BeginEventHandler beginEventHandler, CancelEventHandler cancelEventHandler, EndEventHandler endEventHandler, TickEventHandler tickEventHandler, ErrorEventHandler errorEventHandler, CancelRequested cancelRequested, double minStartTime, int dataCollectionLength)`**
|
||||
*Overload 2 (full implementation)* — writes the `Test` object to an `.xlsx` file at `pathname`.
|
||||
- Uses a template file (`XLSXExportTemplate.xlsx`) located in `ReportTemplates`.
|
||||
- Writes metadata (inception date/time, test ID, description) to fixed cells in the `"Data"` worksheet.
|
||||
- Writes per-channel metadata (sample rate, filter cutoff, units, etc.) to rows 6–23.
|
||||
- Writes time-series data starting at row 24.
|
||||
- Applies filtering *only if* `Filtered` is `true` and `bFiltering` is `true`.
|
||||
- Uses SAX-style streaming (`OpenXmlReader`/`OpenXmlWriter`) for efficient large-data export.
|
||||
- Fires progress (`tickEventHandler`), error (`errorEventHandler`), and completion (`endEventHandler`) callbacks.
|
||||
- Clears `RowIndexToRow` and `_stringLookup` caches before each write.
|
||||
- Forces full recalculation on load (`ForceFullCalculation = true`, `FullCalculationOnLoad = true`).
|
||||
- Adds a date/time number format style (`NumberFormatId = 14`) to the stylesheet.
|
||||
- Releases channel data (`UnSet()`) and triggers full garbage collection after writing.
|
||||
|
||||
- **`public void Initialize(...)`**
|
||||
*Overload* — currently has no body.
|
||||
|
||||
- **`private static Common.DAS.Concepts.DataScaler GetDataScaler(Test.Module.AnalogInputChannel)`**
|
||||
Constructs and configures a `DataScaler` instance from an `AnalogInputChannel`, including linearization, scaling, zeroing, and excitation parameters.
|
||||
|
||||
- **`protected Cell GetCell(Worksheet worksheet, string xColumn, UInt32 rowIndex, bool bLookForCell = true)`**
|
||||
Retrieves or inserts a cell at the given column and row. Uses `RowIndexToRow` cache for performance.
|
||||
|
||||
- **`private static Cell InsertCellInWorksheet(...)`**
|
||||
Inserts a cell into the worksheet, maintaining Open XML cell ordering requirements.
|
||||
|
||||
- **`private void WriteTime(...)` / `WriteDate(...)` / `WriteDouble(...)` / `WriteString(...)`**
|
||||
Helper methods to write typed values into cells, using shared strings for text and appropriate cell types/styles.
|
||||
|
||||
- **`private static string GetColumn(int index)`**
|
||||
Converts a zero-based column index to Excel column letters (e.g., `0 → "B"`, `1 → "C"`). *Note: Starts at column B (index 0), not A.*
|
||||
|
||||
- **`private int InsertSharedStringItem(string text, SharedStringTablePart)`**
|
||||
Inserts or retrieves a shared string index. Uses `_stringLookup` dictionary for O(1) lookup.
|
||||
|
||||
- **`private void AddStyleSheet(SpreadsheetDocument)`**
|
||||
Adds a date/time number format (`NumberFormatId = 14`) to the stylesheet and caches its index.
|
||||
|
||||
- **`internal Writer(File fileType, int encoding)`**
|
||||
Constructor. Sets default export flags: `ExportADC = false`, `ExportEU = true`, `ExportMv = false`.
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
|
||||
- **Cell ordering**: Cells in a row must be in ascending `CellReference` order (enforced by `InsertCellInWorksheet`).
|
||||
- **Shared string uniqueness**: `_stringLookup` ensures each unique string is stored only once in the shared string table.
|
||||
- **Data row indexing**: Time-series data rows start at row 24 (`24 + sampleIndex`).
|
||||
- **Channel column indexing**: Columns are assigned sequentially starting at column B (`GetColumn(i)` where `i = 0` → `"B"`).
|
||||
- **Metadata row layout** (fixed per channel):
|
||||
- Row 6: Sample rate (Hz)
|
||||
- Row 7: AA filter rate (Hz)
|
||||
- Row 8: Channel index (1-based)
|
||||
- Row 9: ISO code
|
||||
- Row 10: Channel name (`ChannelName2`)
|
||||
- Row 12: Serial number
|
||||
- Row 13: Filter cutoff (Hz) — `0` if not filtered
|
||||
- Row 14: Filter name — only if filtered
|
||||
- Row 15: Engineering units
|
||||
- Row 17: Pre-trigger samples
|
||||
- Row 18: Post-trigger samples
|
||||
- Row 19: `DataZeroLevelAdc`
|
||||
- Row 20: ADC-to-EU scaling factor
|
||||
- Row 21: ADC-to-mV scaling factor
|
||||
- Row 23: Channel label (`"Chan {i}: {name}"`)
|
||||
- **Time calculation**: Time value for sample `n` is computed as:
|
||||
```
|
||||
time = (StartRecordSampleNumber - TriggerSampleNumber[0] + n) / SampleRateHz
|
||||
```
|
||||
where `n` is adjusted for `minStartTime` and per-channel start offsets.
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
|
||||
#### External Dependencies
|
||||
- **`DocumentFormat.OpenXml`** — Core Open XML SDK for reading/writing `.xlsx` files.
|
||||
- **`DTS.Common.Utilities.Logging`** — Uses `APILogger.Log(...)` for non-fatal exceptions (e.g., `WindowAverageADC` failures).
|
||||
- **`DTS.Slice.Control`** — Imports `FilteredData`, `FilteredChannelData`, and related filtering types.
|
||||
|
||||
#### Internal Dependencies
|
||||
- **`DTS.Serialization`** — Inherits from `Serialization.File`.
|
||||
- **`DTS.Common.DAS.Concepts`** — Uses `DataScaler` and related types.
|
||||
- **`DTS.Slice.Control`** — Uses `SaeJ211Filter`, `FilteredData`, and `CancelRequested`.
|
||||
- **`Test` model** — Expects `Test.Module.AnalogInputChannel`, `Test.Module.Channel`, and `PersistentChannelInfo` with `Data` array.
|
||||
|
||||
#### Dependencies *on* this Module
|
||||
- Any code requiring XLSX export of `Test` objects (e.g., UI export buttons, batch processing pipelines) will instantiate `DTS.Serialization.XLSX.File` and call `Exporter.Write(...)`.
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
|
||||
- **Column offset**: `GetColumn` starts at column B (index 0 → `"B"`), not A. This is hardcoded and not configurable.
|
||||
- **String caching**: `_stringLookup` is reset per `Write` call (cleared in `Write`), but reused *within* a single write for efficiency. Not thread-safe.
|
||||
- **Row caching**: `RowIndexToRow` is a static dictionary. It is cleared at the start of each `Write`, but if multiple threads call `Write` concurrently, race conditions may occur.
|
||||
- **Filtered data is precomputed**: When `Filtered = true`, *all* EU data is pre-filtered into a `double[][]` before streaming. This may consume significant memory for large datasets.
|
||||
- **Template dependency**: Requires `XLSXExportTemplate.xlsx` in the `ReportTemplates` subdirectory of the application base directory. Missing file → copy failure.
|
||||
- **GC pressure mitigation**: Explicit `GC.Collect()` and heap compaction are triggered *after* writing. This may cause latency spikes.
|
||||
- **No export flag enforcement in data loop**: The `Write` method *only* exports EU data (via `ds.GetEU(...)`), regardless of `ExportADC`, `ExportEU`, or `ExportMV` settings. These flags are set on the `Writer`, but the current implementation ignores them in the data loop.
|
||||
- **`FilteredChannelData` is commented out**: The property `FilteredChannelData` is commented out in `Excel.File.Writer.cs`, suggesting incomplete or deprecated functionality.
|
||||
- **`UseLegacyTDCSoftwareFiltering` is used but not defined**: In the filtering loop, `UseLegacyTDCSoftwareFiltering` is referenced but not declared in the visible scope — likely a field or property defined elsewhere in the `Writer` class (not shown).
|
||||
- **`minStartTime` is used but not validated**: Assumes `minStartTime` ≤ actual start time of data; no bounds checking is evident.
|
||||
- **`filteredData` is set to `null` after use**: A manual nulling of `filteredData` is done, but this may be redundant with the end of scope — possibly legacy cleanup.
|
||||
|
||||
---
|
||||
|
||||
*Documentation generated from source files `Excel.File.cs` and `Excel.File.Writer.cs`.*
|
||||
Reference in New Issue
Block a user