--- source_files: - DataPRO/TDASCommands/TestTriggerCommands.cs - DataPRO/TDASCommands/CommandBase.cs - DataPRO/TDASCommands/TDASCommandPacketBase.cs generated_at: "2026-04-16T03:47:17.202169+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "095345d9b2c6bf7d" --- # TDASCommands **Documentation: TDAS Test Trigger Commands Module** --- ### 1. Purpose This module implements command classes for interacting with TDAS hardware modules to perform test trigger operations—specifically, arming, querying status, and disabling the trigger. It provides two public command types: `TestTrigger` (single-module, unicast) and `TestTriggerBroadcast` (single-module broadcast, unicast to a specific module index). These commands construct and send ASCII-based protocol commands (`TESTTRIG` or `*TESTTRIG`) to TDAS devices and parse the ASCII response to extract the trigger status (`ARMED` or `OFF`). The module relies on the shared `CommandBase` and `TDASCommandPacketBase` infrastructure for communication, sequencing, and response handling. --- ### 2. Public Interface #### `TestTrigger` class *Public, concrete command class for single-module test trigger operations.* - **`int ModuleIndex`** Gets or sets the module index (0–9). Setting it enforces `<10` and disables `RackCommand`. - **`SubCommandValues SubCommand`** Gets/sets the subcommand to send: `ARM`, `STATUS`, or `OFF`. - *Getter* parses `_CommandString.SubCommand` as `SubCommandValues`. - *Setter* writes the enum value as a string into `_CommandString.SubCommand`. - **`StatusValues TriggerStatus`** Gets the parsed trigger status from the last response: `ARMED` or `OFF`. - *Getter* parses `_CommandString.Status` as `StatusValues`. - Value is populated during `ProcessData()`. - **`TestTrigger(ICommunication sock)`** Constructor with default 30s timeout. Initializes `TDASCommandPacketBase` with `TestTriggerCommandString`, sets `RebuildBytes = true`, `RackCommand = false`, and default `SubCommand = STATUS`. - **`TestTrigger(ICommunication sock, int msTimeout)`** Constructor with configurable timeout. Same initialization as above, but uses provided timeout. #### `TestTriggerBroadcast` class *Public, concrete command class for broadcast test trigger to a specific module.* - **`SubCommandValues SubCommand`** Same semantics as `TestTrigger.SubCommand`, operating on `_CommandString.SubCommand` of the underlying `TestTriggerBroadcastCommandString`. - **`TestTriggerBroadcast(ICommunication sock, int moduleIndex)`** Constructor with default timeout. Initializes `TDASCommandPacketBase` with `TestTriggerBroadcastCommandString(moduleIndex)`, sets `RackCommand = false`, `RebuildBytes = true`, and default `SubCommand = STATUS`. - **`TestTriggerBroadcast(ICommunication sock, int moduleIndex, int msTimeout)`** Constructor with configurable timeout. Same initialization as above. #### Internal helper classes (not part of public API, but referenced for completeness) - **`TestTriggerCommandString`** *Internal* subclass of `CommandString`. - `_CommandString => "TESTTRIG"` - `_CommandDescription => "Test trigger"` - `SubCommand` and `Status` properties (string) store subcommand and response status. - `GetParameters()` returns `" "` as ASCII bytes. - **`TestTriggerBroadcastCommandString`** *Internal* subclass of `CommandString`. - `_CommandString => "*TESTTRIG"` (if `ModuleIndex >= 0`) or `"*TESTTRIG"` otherwise. - `_CommandDescription` mirrors `_CommandString`. - `ModuleIndex`, `SubCommand` properties. - Constructor accepts `moduleIndex`. - `GetParameters()` same as `TestTriggerCommandString`. --- ### 3. Invariants - **ModuleIndex constraint**: `ModuleIndex` must be `<10` (enforced in `TDASCommandPacketBase.ModuleIndex` setter). Setting it to `>=10` throws an exception. - **RackCommand mutual exclusion**: Setting `ModuleIndex` in `TDASCommandPacketBase` sets `RackCommand = false`. `RackCommand` is only `true` when `ModuleIndex` is unset (default `' '` space) and not explicitly set to a digit. - **Default subcommand**: All constructors initialize `_CommandString.SubCommand = "STATUS"`. - **Response parsing invariant**: `ProcessData()` in `TestTrigger` parses the response into tokens; status is assigned from `tokens[1]` if `tokens.Length >= 2`. If parsing fails, `_CommandString.Status` remains unchanged. - **Response format assumption**: TDAS responses are ASCII, newline-terminated (`\r\n`), and contain the command string followed by a space and status (e.g., `TESTTRIG ARMED\r\n`). Parsing assumes this format. - **`RebuildBytes = true`**: All `TestTrigger*` constructors set `RebuildBytes = true`, ensuring `CommandString.GetBytes()` regenerates the byte array on each `ToBytes()` call (critical for dynamic `SubCommand` changes). --- ### 4. Dependencies #### Imports / References (from source): - `DTS.Common.ICommunication` → `ICommunication` interface for socket communication. - `DTS.DASLib.Command.TDAS` namespace: - `CommandBase` (base class for all commands, provides `ProcessData`, `ResponseData`, `SyncExecute`, throttling). - `TDASCommandPacketBase` (packet construction, verification, MDB mode support). - `CommandString` (abstract base for command strings). - `System.Text.Encoding` (ASCII encoding/decoding). - `System.Threading` (used in `CommandBase` for `SemaphoreSlim` throttling). #### Inferred callers: - Likely instantiated by higher-level test or configuration logic (e.g., test harnesses, calibration tools). - Uses `CommandBase` infrastructure, so depends on: - `APILogger` (for logging errors and command/response). - Throttling via `CommandBase.InitializeSemaphore()` (default: 3 concurrent operations, 100ms delay). #### Dependencies on other modules: - `TDASCommandPacketBase` → depends on `MDB_BLOCK` (for data mode parsing), `CommandPacketBase` (base), and `CommandString`. - `CommandBase` → depends on logging infrastructure (`TextLogger`, `APILogger`), threading (`SemaphoreSlim`), and `AbstractCommandBase`. --- ### 5. Gotchas - **`ModuleIndex` parsing is fragile**: `ModuleIndex` getter in `TDASCommandPacketBase` uses `int.Parse(new string(_moduleIndex, 1))`. If `_moduleIndex` is `' '` (space), this throws `FormatException`. This is avoided in `TestTrigger` constructors because `ModuleIndex` is never explicitly set, but if used directly, it may fail. - **`TriggerStatus` may be stale or empty**: `TriggerStatus` reads `_CommandString.Status`, which is only updated in `ProcessData()`. If `ResponseData` is accessed before `ProcessData()` runs (e.g., via `ResponseData` getter), `ProcessData()` executes—but if the response is malformed or missing, `_CommandString.Status` may remain `null` or unchanged, causing `Enum.Parse` to throw. - **`ProcessData()` in `TestTrigger` is custom and narrow**: Unlike `CommandBase.ProcessData()`, `TestTrigger.ProcessData()` manually parses the response using `GetCommandPortion()` and `ResponseData.Split`. It assumes the response contains the command string followed by a space and status. Deviations (e.g., extra whitespace, different order) may cause parsing failure. - **No validation of `SubCommand` enum values in setter**: `SubCommand` setter directly assigns `value.ToString()` to `_CommandString.SubCommand`. If an invalid enum value is passed (e.g., via reflection or cast), no validation occurs—though `Enum.Parse` in getter may throw. - **`TestTriggerBroadcastCommandString.ModuleIndex` is not validated**: The broadcast command accepts any `moduleIndex`, but the command string uses `*TESTTRIG`. If `moduleIndex < 0`, it falls back to `*TESTTRIG` (broadcast to all modules). This may be unintended. - **Throttling is global and static**: `CommandBase` uses static `_pool` and `_semaphoreDelay`. If `InitializeSemaphore()` is not called, defaults (`spots=3`, `delay=100ms`) apply. This affects all `TestTrigger`/`TestTriggerBroadcast` instances. - **`RebuildBytes` must be `true` for dynamic updates**: If `RebuildBytes` is accidentally set to `false`, changing `SubCommand` will not affect the outgoing command bytes until `RebuildBytes = true` or `cs.RebuildBytes()` is called. - **No error handling in `ProcessData()` for malformed responses**: If `ResponseData` does not contain the expected format (e.g., missing `\r\n`, insufficient tokens), `ProcessData()` silently returns without updating `_CommandString.Status`. This may lead to stale status values. - **`GetParameters()` returns a leading space**: Both `TestTriggerCommandString` and `TestTriggerBroadcastCommandString` return `" "` (note leading space). This matches TDAS protocol expectations but is non-obvious. - **`ModuleIndex` setter in `TDASCommandPacketBase` throws on `>=10`**: This is a hard constraint. If future hardware supports >10 modules, this will break. - **`ExpectsData = true` by default in `CommandString`**: `TestTrigger`/`TestTriggerBroadcast` do not override this, so `ExpectsData = true`. If the TDAS response for `TESTTRIG` is status-only (no data), `VerifyPacket()` may behave unexpectedly (see `TDASCommandPacketBase.VerifyPacket()` logic). - **`ToCommandString()` strips control characters**: `ToCommandString()` removes `\r\n` and `\0`, which may obscure debugging if raw bytes are needed. - **`CommandBase.ProcessData()` may throw**: If `ResponseData` contains `"ERR"`, `ProcessData()` throws `InvalidOperationException`. This is caught only if the caller handles it. - **`TestTriggerBroadcast` does not expose `ModuleIndex`**: The `moduleIndex` is stored in the internal `TestTriggerBroadcastCommandString`, but not exposed as a property. Callers must track it externally. --- *End of documentation.*