221 lines
15 KiB
Markdown
221 lines
15 KiB
Markdown
|
|
---
|
|||
|
|
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`.
|