--- source_files: - Common/DTS.Common.DataModel/StateMachines/OverallArmStatusStateMachine.cs generated_at: "2026-04-16T03:32:13.517351+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "8fbd8ac85721cb74" --- # StateMachines ## Documentation: `OverallArmStatusStateMachine` --- ### **1. Purpose** The `OverallArmStatusStateMachine` class implements a state machine that tracks and manages the high-level operational status of an arm subsystem (likely related to data acquisition or recording hardware) within the DTS system. It uses the `Stateless` library to define transitions between states such as `Recording`, `IDLE`, `WaitingForTrigger`, `Downloading`, and `Disarmed`, based on triggers like `Recording`, `DoneRecording`, `Disarm`, and `DASNotFound`. Its primary role is to maintain a canonical "overall arm status" state, emit notifications on state changes via the `OverallStatusStateChange` event, and serve as a central coordination point for status reporting across the application (e.g., updating a global status UI field). It does *not* manage low-level arm logic but aggregates and reflects higher-level transitions. --- ### **2. Public Interface** #### **Constructor** ```csharp public OverallArmStatusStateMachine() ``` - Initializes the `IEventAggregator` via `ContainerLocator.Container.Resolve()`. - Calls `Initialize()` to configure the underlying `Stateless.StateMachine`. #### **Events** ```csharp public event OverallStatusStateChangeDelegate OverallStatusStateChange; ``` - **Delegate**: `public delegate void OverallStatusStateChangeDelegate(ArmStateMachineStates.States previousState, ArmStateMachineStates.States nextState);` - Fired whenever the overall status transitions to a new state (i.e., `CurrentOverallStatusState` changes). The event includes the previous and next state. #### **Methods** ```csharp public ArmStateMachineStates.States GetDASStatus() ``` - Returns the current overall status state (`CurrentOverallStatusState`). ```csharp public void FireTrigger(Triggers trigger, ArmStateMachineStates.States state) ``` - Fires a named trigger with an associated *target state parameter* (note: this is unusual—see *Gotchas*). - Internally maps each `Triggers` enum value to a pre-configured `TriggerWithParameters` and invokes `StateMachine.Fire(trigger, state)`. - Logs exceptions via `APILogger.Log(ex.Message)`; does *not* rethrow. - **Special case**: `Triggers.PostTestProcessing` incorrectly fires `DoneRecordingTrigger` instead of a dedicated `PostTestProcessingTrigger`. #### **Nested Types** - `public enum Triggers`: Defines 37+ named triggers (e.g., `Recording`, `Disarm`, `DASNotFound`, `Downloading`, `WaitingForTrigger`, `WaitingForSchedule`, `WaitingForInterval`, `ReadyForDownload`, `DoneRecording`, `NoDataToDownload`, `DataNeverDownloaded`, `Streaming`, `FlashClear`, `Error`, `GettingEventInfo`, `CheckingForData`, `Rearming`, `IDLE`, `IntervalRecording`, `NonIntervalRecording`, `RunButton`, `a`, `c`, `d`, `e`, `h`, `n`, `rr`, `tt`, `uu`, `yy`). - *Note*: Several triggers (`a`, `c`, `d`, `e`, `h`, `n`, `rr`, `tt`, `uu`, `yy`) appear to be placeholder or legacy names with no documented purpose. --- ### **3. Invariants** - **Initial State**: The state machine always starts in `ArmStateMachineStates.States.CheckingForDAS`. - **Current State Tracking**: `CurrentOverallStatusState` is updated *only* via `SetOverallStatus()`, which: - Compares `newState` to `CurrentOverallStatusState`. - Logs transitions via `APILogger.Log(...)`. - Invokes `OverallStatusStateChange` *only if* the state changes. - **State Machine Library**: Uses `Stateless.StateMachine`. - **Parameterized Triggers**: All transitions that accept a state parameter use `SetTriggerParameters()`, meaning every trigger expects a *target state* as an argument when fired (e.g., `Fire(trigger, targetState)`). - **No Explicit Error Handling in Transitions**: Transitions do not define custom `OnEntryFrom`/`OnExit` logic beyond calling `SetOverallStatus()`; no fallback or recovery behavior is defined in the state configuration. --- ### **4. Dependencies** #### **Imports/Usings** - `Stateless` – Core state machine library. - `Prism.Ioc.ContainerLocator` – For resolving `IEventAggregator`. - `DTS.Common.Enums.TSRAIRGo` – Provides `ArmStateMachineStates.States` (not shown in this file). - `DTS.Common.Utilities.Logging` – Provides `APILogger`. - `System` and `Prism.Events` – For `IEventAggregator`. #### **External Dependencies** - **`ArmStateMachineStates.States`**: An external enum defining the valid states (e.g., `CheckingForDAS`, `IDLE`, `Recording`, `Disarmed`, `Downloading`, `ClearingFlash`, `WaitingForTrigger`, `WaitingForSchedule`, `WaitingForInterval`, `PostTestProcessing`, `GettingEventInfo`, `ReadyForDownload`, `Streaming`). Its definition is not included here. - **`APILogger`**: Static logging utility. - **`ContainerLocator`**: Prism DI container accessor (assumes `IEventAggregator` is registered). #### **Consumers** - Any component needing to update or query the overall arm status (e.g., UI, telemetry, control logic) must: - Subscribe to `OverallStatusStateChange` to react to state changes. - Call `FireTrigger()` to signal events. - Call `GetDASStatus()` to poll the current state. --- ### **5. Gotchas** - **Unusual Trigger Signature**: All triggers are defined as `TriggerWithParameters`, meaning every `Fire()` call *must* supply a target state (e.g., `Fire(RecordingTrigger, ArmStateMachineStates.States.Recording)`). This is atypical—most state machines infer the next state from the transition configuration. The comment in `FireTrigger()` ("why specify state here? shouldn't that be done based on current state/trigger?") confirms this design is questionable and likely error-prone. - **Incorrect Trigger Mapping**: In `FireTrigger()`, `Triggers.PostTestProcessing` incorrectly fires `DoneRecordingTrigger` instead of a dedicated `PostTestProcessingTrigger`. This may cause unintended state transitions (e.g., skipping `PostTestProcessing` state entirely). - **Unused Triggers**: The `Triggers` enum includes 10 cryptic triggers (`a`, `c`, `d`, `e`, `h`, `n`, `rr`, `tt`, `uu`, `yy`) with no corresponding configuration in `Initialize()`. These are likely legacy or placeholders and should be removed or documented. - **No Handling for `ErrorTrigger`**: While `ErrorTrigger` is declared, it is *not* used in any state configuration (no `.Permit()` or `.OnEntryFrom()` references it). Attempting to fire it will throw a `Stateless` exception (trigger not defined for current state). - **Ignored Triggers May Cause Silent Failures**: Several states use `.Ignore()` for specific triggers (e.g., `ClearingFlash` ignores `ReadyForDownload`, `NoDataToDownload`, `DataNeverDownloaded`). Firing these triggers in those states will throw an exception (not silently ignored), contradicting the intent of `.Ignore()` in `Stateless` (which *does* allow the trigger but prevents transition). Verify `Stateless` behavior—this may be a source of runtime exceptions. - **No Public Setter for State**: The current state is read-only via `GetDASStatus()`. There is no way to manually override or reset the state machine (e.g., for testing or recovery), which may complicate error recovery. - **Logging Side Effect**: `SetOverallStatus()` logs *every* transition, which may be excessive in high-frequency scenarios. No filtering or throttling is applied. - **Missing State Definitions**: The states used (e.g., `ArmStateMachineStates.States.CheckingForDAS`) are referenced but not defined in this file. Their semantics and relationships depend on the external `ArmStateMachineStates.States` enum. - **No Validation on State Parameter**: `FireTrigger()` accepts any `ArmStateMachineStates.States` as the second parameter. Passing an invalid or inconsistent state (e.g., `Fire(RecordingTrigger, ArmStateMachineStates.States.Disarmed)`) may result in runtime exceptions or undefined behavior. - **Exception Swallowing**: `FireTrigger()` catches and logs *all* exceptions (including `Stateless` exceptions like `InvalidOperationException` for invalid transitions), but does not propagate them. This can mask critical failures. - **No Thread Safety**: The class does not indicate thread-safety. Concurrent calls to `FireTrigger()` or state queries may cause race conditions. - **Graph Generation Side Effect**: `Stateless.Graph.UMLDotGraph.Format(...)` is called but the result is discarded (`string graph = ...; graph = ...;`). This suggests debugging code was left in place. --- *Documentation generated from source file `Common/DTS.Common.DataModel/StateMachines/OverallArmStatusStateMachine.cs`.*