Files
DP44/enriched-qwen3-coder-next/Common/DTS.Common.DataModel/StateMachines.md
2026-04-17 14:55:32 -04:00

8.7 KiB
Raw Blame History

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
Common/DTS.Common.DataModel/StateMachines/OverallArmStatusStateMachine.cs
2026-04-16T03:32:13.517351+00:00 Qwen/Qwen3-Coder-Next-FP8 1 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

public OverallArmStatusStateMachine()
  • Initializes the IEventAggregator via ContainerLocator.Container.Resolve<IEventAggregator>().
  • Calls Initialize() to configure the underlying Stateless.StateMachine.

Events

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

public ArmStateMachineStates.States GetDASStatus()
  • Returns the current overall status state (CurrentOverallStatusState).
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.