Files

145 lines
10 KiB
Markdown
Raw Permalink Normal View History

2026-04-17 14:55:32 -04:00
---
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).