--- 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` 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` - **`public File()`** Constructor. Initializes the base class with `"XLSX"` as the file type identifier. - **`public IWriter 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, IWriter` - **`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`.*