--- source_files: - Common/DTS.Common.Serialization/IRIGCH10/Utils/Utils.cs generated_at: "2026-04-16T03:42:52.923027+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "675d2f03b19fde67" --- # Utils ## Documentation: `DTS.Serialization.IRIGCH10.Utils.Utils` --- ### 1. Purpose This module provides low-level utility functions for handling IRIG CH10 (Inter-Range Instrumentation Group Command Handler, Chapter 10) data format conventions. Specifically, it supports conversion of integer values to Binary-Coded Decimal (BCD) representation (for fields like dates), and computation of checksums (8-bit, 16-bit, and 32-bit) as required by the CH10 specification. It also offers bit-level manipulation helpers for packing/unpacking bitfields from `BitArray` objects—common when serializing/deserializing packet headers and metadata fields. --- ### 2. Public Interface All members are `static` and defined in the `abstract` class `Utils`. No public constructors or instance members exist. | Method | Signature | Behavior | |--------|-----------|----------| | `GetBCDBytes` | `public static byte[] GetBCDBytes(int value)` | Converts an integer `value` (0–9999) into a 2-byte BCD representation (least significant digit in lower nibble of byte 0). Throws `ArgumentOutOfRangeException` if `value` is outside [0, 9999]. | | `GetCheckSum8` | `public static ushort GetCheckSum8(byte[] bytes)` | Computes an 8-bit checksum by summing all bytes in `bytes` and returning the low 16 bits of the sum (i.e., `sum & 0xFFFF`). No padding or alignment assumptions. | | `GetCheckSum16` | `public static ushort GetCheckSum16(byte[] bytes)` | Computes a 16-bit checksum per CH10 spec: interprets `bytes` as an array of `ushort` (little-endian, via `Buffer.BlockCopy`) and sums all `ushort` values. **Requires** `bytes.Length` to be even; asserts this via `Trace.Assert`. | | `GetCheckSum32` | `public static uint GetCheckSum32(byte[] bytes)` | Computes a 32-bit checksum per CH10 spec: interprets `bytes` as an array of `uint` (little-endian) and sums all `uint` values. **Requires** `bytes.Length` to be divisible by 4; asserts this via `Trace.Assert`. | | `BitArrayToInt32` | `public static int BitArrayToInt32(BitArray ba, int startIndex, int endIndex)` | Extracts bits from `ba` between `startIndex` and `endIndex` (inclusive), interpreting them as a little-endian integer (bit 0 = LSB). Returns an `int` (up to 32 bits). | | `SetBits` | `public static void SetBits(BitArray b, uint value, int startIndex, int endIndex)` | Writes the least-significant bits of `value` (covering `(endIndex - startIndex + 1)` bits) into `b`, starting at `startIndex`. Bits are copied in little-endian order (bit 0 of `value` → `b[startIndex]`). | --- ### 3. Invariants - **BCD Range**: `GetBCDBytes` enforces `0 ≤ value ≤ 9999`. Values outside this range throw `ArgumentOutOfRangeException`. - **Checksum Input Length**: - `GetCheckSum16` requires `bytes.Length % 2 == 0`. - `GetCheckSum32` requires `bytes.Length % 4 == 0`. - These are enforced via `Trace.Assert`, which may be compiled out in Release builds—**no runtime exception is thrown** if the invariant is violated in non-Debug builds. - **Bit Index Bounds**: `BitArrayToInt32` and `SetBits` assume `0 ≤ startIndex ≤ endIndex < ba.Length` (or `b.Length`). No explicit bounds checking is performed; out-of-range indices will cause `IndexOutOfRangeException` at runtime. - **Endianness**: All multi-byte integer interpretations (via `Buffer.BlockCopy` into `ushort[]`/`uint[]`) assume **little-endian byte order**, consistent with .NET’s default on most platforms. --- ### 4. Dependencies **Imports/Usings**: - `System` - `System.Collections` (`BitArray`) **Used By**: - Other modules in `DTS.Serialization.IRIGCH10` (inferred from namespace), particularly those handling packet serialization/deserialization (e.g., header construction, data packet checksumming, date/time field encoding). **Used For**: - Encoding/decoding BCD fields (e.g., timestamps, counters). - Computing checksums for CH10 packet headers (`GetCheckSum16`) and data payloads (`GetCheckSum32`). - Bit-level manipulation of packet fields (e.g., flags, variable-length integers). --- ### 5. Gotchas - **`Trace.Assert` is not a runtime guard**: In non-Debug builds, failed assertions in `GetCheckSum16` and `GetCheckSum32` will not throw exceptions—invalid input lengths may cause silent corruption or incorrect checksums. Callers must ensure input alignment themselves. - **BCD encoding is fixed to 4 decimal digits**: `GetBCDBytes` only supports values up to 9999 (2 bytes). Larger values require multiple calls or a different approach (not provided here). - **Little-endian assumption**: `GetCheckSum16`/`GetCheckSum32` rely on `Buffer.BlockCopy` interpreting bytes as little-endian `ushort`/`uint`. This is platform-dependent on .NET (true on x86/x64), but may break on big-endian systems. - **No overflow handling in checksums**: Sums wrap around modulo 2¹⁶ (for `ushort`) or 2³² (for `uint`), per CH10 spec—but this is implicit, not documented in code. - **`SetBits` uses `BitConverter.GetBytes(value)`**: This assumes little-endian layout for `value`, and only the lowest `(endIndex - startIndex + 1)` bits are copied. If `value` has more bits set than `endIndex - startIndex + 1`, higher bits are silently ignored. No validation ensures `value` fits the bit range. - **`BitArrayToInt32` uses LSB-first indexing**: Bit 0 of the result corresponds to `ba[startIndex]`, not `ba[endIndex]`. This matches CH10’s typical bit numbering but may be counterintuitive. None identified beyond the above.