290 lines
17 KiB
Markdown
290 lines
17 KiB
Markdown
---
|
||
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 |