121 lines
8.7 KiB
Markdown
121 lines
8.7 KiB
Markdown
---
|
||
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`.* |