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

325 lines
14 KiB
Markdown

---
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`