Files
DP44/enriched-qwen3-coder-next/Common/DTS.Common.DataModel/StateMachines.md

121 lines
8.7 KiB
Markdown
Raw Normal View History

2026-04-17 14:55:32 -04:00
---
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<IEventAggregator>()`.
- 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<ArmStateMachineStates.States>` 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<ArmStateMachineStates.States, Triggers>`.
- **Parameterized Triggers**: All transitions that accept a state parameter use `SetTriggerParameters<ArmStateMachineStates.States>()`, 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<ArmStateMachineStates.States>`, 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`.*