using Stateless; using Prism.Ioc; using DTS.Common.Enums.TSRAIRGo; using DTS.Common.Utilities.Logging; using System; using Prism.Events; namespace DTS.Common.DataModel.StateMachines { public class OverallArmStatusStateMachine { private readonly IEventAggregator _eventAggregator; private StateMachine overallArmStatusStateMachine = null; private StateMachine.TriggerWithParameters NoDataToDownloadTrigger; private StateMachine.TriggerWithParameters DataNeverDownloadedTrigger; private StateMachine.TriggerWithParameters DASNotFoundTrigger; private StateMachine.TriggerWithParameters FlashClearTrigger; private StateMachine.TriggerWithParameters WaitingForTriggerTrigger; private StateMachine.TriggerWithParameters WaitingForScheduleTrigger; private StateMachine.TriggerWithParameters WaitingForIntervalTrigger; private StateMachine.TriggerWithParameters RecordingTrigger; private StateMachine.TriggerWithParameters DoneRecordingTrigger; private StateMachine.TriggerWithParameters ErrorTrigger; private StateMachine.TriggerWithParameters CheckingForDataTrigger; private StateMachine.TriggerWithParameters GettingEventInfoTrigger; private StateMachine.TriggerWithParameters ReadyForDownloadTrigger; private StateMachine.TriggerWithParameters DownloadTrigger; private StateMachine.TriggerWithParameters DownloadCleaningUpTrigger; private StateMachine.TriggerWithParameters DownloadFinishedTrigger; private StateMachine.TriggerWithParameters IDLETrigger; private StateMachine.TriggerWithParameters StreamingTrigger; private StateMachine.TriggerWithParameters DisarmTrigger; private StateMachine.TriggerWithParameters RearmingTrigger; ArmStateMachineStates.States CurrentOverallStatusState = ArmStateMachineStates.States.CheckingForDAS; /// /// Initialize the Event Aggregator and the Overall Arm Status state machine. /// public OverallArmStatusStateMachine() { _eventAggregator = ContainerLocator.Container.Resolve(); Initialize(); } public enum Triggers { bFillingBuffer, CheckingForData, ConfigurationIsSet, DASNotFound, DataNeverDownloaded, Disarm, DoneRecording, Downloading, DownloadCleaningUp, DownloadFinished, Error, Faulted, FlashClear, GettingEventInfo, IDLE, IntervalRecording, NoDataToDownload, NonIntervalRecording, PostTestProcessing, ReadyForDownload, Rearming, Recording, RunButton, Streaming, WaitingForTrigger, WaitingForSchedule, WaitingForInterval, a, c, d, e, h, n, rr, tt, uu, yy } private void Initialize() { overallArmStatusStateMachine = new StateMachine(ArmStateMachineStates.States.CheckingForDAS); NoDataToDownloadTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.NoDataToDownload); DataNeverDownloadedTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.DataNeverDownloaded); DASNotFoundTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.DASNotFound); FlashClearTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.FlashClear); RecordingTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.Recording); DoneRecordingTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.DoneRecording); WaitingForTriggerTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.WaitingForTrigger); WaitingForScheduleTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.WaitingForSchedule); WaitingForIntervalTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.WaitingForInterval); CheckingForDataTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.CheckingForData); ErrorTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.Error); GettingEventInfoTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.GettingEventInfo); ReadyForDownloadTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.ReadyForDownload); DownloadTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.Downloading); DownloadCleaningUpTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.DownloadCleaningUp); DownloadFinishedTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.DownloadFinished); IDLETrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.IDLE); StreamingTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.Streaming); DisarmTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.Disarm); RearmingTrigger = overallArmStatusStateMachine.SetTriggerParameters(Triggers.Rearming); //--------------------CheckingForDAS-------------------- overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.CheckingForDAS) .OnEntryFrom(DASNotFoundTrigger, o => SetOverallStatus(o)) .OnEntryFrom(FlashClearTrigger, o => SetOverallStatus(o)) .OnEntryFrom(ReadyForDownloadTrigger, o => SetOverallStatus(o)) .PermitReentry(Triggers.DASNotFound) .Permit(Triggers.Recording, ArmStateMachineStates.States.Recording) .Permit(Triggers.ReadyForDownload, ArmStateMachineStates.States.IDLE) .Permit(Triggers.NoDataToDownload, ArmStateMachineStates.States.IDLE) .Permit(Triggers.DataNeverDownloaded, ArmStateMachineStates.States.IDLE) .Permit(Triggers.DoneRecording, ArmStateMachineStates.States.IDLE) .Permit(Triggers.Streaming, ArmStateMachineStates.States.Streaming) .Permit(Triggers.FlashClear, ArmStateMachineStates.States.ClearingFlash) .Permit(Triggers.WaitingForTrigger, ArmStateMachineStates.States.WaitingForTrigger) .Permit(Triggers.WaitingForSchedule, ArmStateMachineStates.States.WaitingForSchedule) .Permit(Triggers.WaitingForInterval, ArmStateMachineStates.States.WaitingForInterval); //--------------------IDLE-------------------------------- overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.IDLE) .OnEntryFrom(ReadyForDownloadTrigger, o => SetOverallStatus(o)) .OnEntryFrom(NoDataToDownloadTrigger, o => SetOverallStatus(o)) .OnEntryFrom(DataNeverDownloadedTrigger, o => SetOverallStatus(o)) .OnEntryFrom(DoneRecordingTrigger, o => SetOverallStatus(o)) .OnEntryFrom(FlashClearTrigger, o => SetOverallStatus(o)) .OnEntryFrom(WaitingForTriggerTrigger, o => SetOverallStatus(o)) .OnEntryFrom(StreamingTrigger, o => SetOverallStatus(o)) .Permit(Triggers.DASNotFound, ArmStateMachineStates.States.CheckingForDAS) .Permit(Triggers.FlashClear, ArmStateMachineStates.States.ClearingFlash) .Permit(Triggers.WaitingForTrigger, ArmStateMachineStates.States.WaitingForTrigger) .Permit(Triggers.WaitingForSchedule, ArmStateMachineStates.States.WaitingForSchedule) .Permit(Triggers.WaitingForInterval, ArmStateMachineStates.States.WaitingForInterval) .PermitReentry(Triggers.ReadyForDownload) .PermitReentry(Triggers.NoDataToDownload) .PermitReentry(Triggers.DataNeverDownloaded) .PermitReentry(Triggers.DoneRecording); //--------------------Streaming-------------------------- overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.Streaming) .OnEntryFrom(StreamingTrigger, o => SetOverallStatus(o)) .Permit(Triggers.DASNotFound, ArmStateMachineStates.States.CheckingForDAS) .Permit(Triggers.DoneRecording, ArmStateMachineStates.States.IDLE) .Permit(Triggers.NoDataToDownload, ArmStateMachineStates.States.IDLE) .PermitReentry(Triggers.Streaming); //--------------------ClearingFlash----------------------- overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.ClearingFlash) .OnEntryFrom(FlashClearTrigger, o => SetOverallStatus(o)) .Ignore(Triggers.ReadyForDownload) .Ignore(Triggers.NoDataToDownload) .Ignore(Triggers.DataNeverDownloaded) .Permit(Triggers.WaitingForTrigger, ArmStateMachineStates.States.WaitingForTrigger) .Permit(Triggers.WaitingForSchedule, ArmStateMachineStates.States.WaitingForSchedule) .Permit(Triggers.WaitingForInterval, ArmStateMachineStates.States.WaitingForInterval) .Permit(Triggers.Disarm, ArmStateMachineStates.States.Disarmed) .Permit(Triggers.Streaming, ArmStateMachineStates.States.Streaming) .Permit(Triggers.DASNotFound, ArmStateMachineStates.States.CheckingForDAS) .PermitReentry(Triggers.FlashClear); //--------------------WaitingForTrigger------------------ overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.WaitingForTrigger) .OnEntryFrom(WaitingForTriggerTrigger, o => SetOverallStatus(o)) .Ignore(Triggers.DataNeverDownloaded) .Permit(Triggers.DASNotFound, ArmStateMachineStates.States.CheckingForDAS) .Permit(Triggers.Recording, ArmStateMachineStates.States.Recording) .Permit(Triggers.DoneRecording, ArmStateMachineStates.States.IDLE) .Permit(Triggers.ReadyForDownload, ArmStateMachineStates.States.IDLE) .Permit(Triggers.NoDataToDownload, ArmStateMachineStates.States.IDLE) .Permit(Triggers.Disarm, ArmStateMachineStates.States.Disarmed) .Permit(Triggers.Rearming, ArmStateMachineStates.States.Rearming) .PermitReentry(Triggers.WaitingForTrigger) .PermitReentry(Triggers.WaitingForSchedule) .PermitReentry(Triggers.WaitingForInterval); //--------------------WaitingForSchedule------------------ overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.WaitingForSchedule) .OnEntryFrom(WaitingForScheduleTrigger, o => SetOverallStatus(o)) .OnEntryFrom(DisarmTrigger, o => SetOverallStatus(o)) .Ignore(Triggers.DataNeverDownloaded) .Permit(Triggers.DASNotFound, ArmStateMachineStates.States.CheckingForDAS) .Permit(Triggers.Recording, ArmStateMachineStates.States.Recording) .Permit(Triggers.DoneRecording, ArmStateMachineStates.States.IDLE) .Permit(Triggers.WaitingForInterval, ArmStateMachineStates.States.WaitingForInterval) .Permit(Triggers.ReadyForDownload, ArmStateMachineStates.States.IDLE) .Permit(Triggers.NoDataToDownload, ArmStateMachineStates.States.IDLE) .Permit(Triggers.Disarm, ArmStateMachineStates.States.Disarmed) .PermitReentry(Triggers.WaitingForSchedule); //--------------------WaitingForInterval------------------ overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.WaitingForInterval) .OnEntryFrom(WaitingForIntervalTrigger, o => SetOverallStatus(o)) .OnEntryFrom(DisarmTrigger, o => SetOverallStatus(o)) .Ignore(Triggers.DataNeverDownloaded) .Permit(Triggers.DASNotFound, ArmStateMachineStates.States.CheckingForDAS) .Permit(Triggers.Recording, ArmStateMachineStates.States.Recording) .Permit(Triggers.DoneRecording, ArmStateMachineStates.States.IDLE) .Permit(Triggers.ReadyForDownload, ArmStateMachineStates.States.IDLE) .Permit(Triggers.NoDataToDownload, ArmStateMachineStates.States.IDLE) .Permit(Triggers.Disarm, ArmStateMachineStates.States.Disarmed) .PermitReentry(Triggers.WaitingForInterval); //--------------------Recording-------------------------- overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.Recording) .OnEntryFrom(RecordingTrigger, o => SetOverallStatus(o)) .OnEntryFrom(DoneRecordingTrigger, o => SetOverallStatus(o)) .OnEntryFrom(WaitingForIntervalTrigger, o => SetOverallStatus(o)) .Permit(Triggers.DASNotFound, ArmStateMachineStates.States.CheckingForDAS) .Permit(Triggers.DoneRecording, ArmStateMachineStates.States.PostTestProcessing) .Permit(Triggers.WaitingForTrigger, ArmStateMachineStates.States.WaitingForTrigger) .Permit(Triggers.WaitingForInterval, ArmStateMachineStates.States.WaitingForInterval) .Permit(Triggers.Rearming, ArmStateMachineStates.States.Rearming) .Permit(Triggers.ReadyForDownload, ArmStateMachineStates.States.IDLE) .Permit(Triggers.NoDataToDownload, ArmStateMachineStates.States.IDLE) .Permit(Triggers.DataNeverDownloaded, ArmStateMachineStates.States.ReadyForDownload) .Permit(Triggers.Disarm, ArmStateMachineStates.States.Disarmed) .PermitReentry(Triggers.Recording); //--------------------Rearming----------------- overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.Rearming) .OnEntryFrom(RecordingTrigger, o => SetOverallStatus(o)) .OnEntryFrom(WaitingForTriggerTrigger, o => SetOverallStatus(o)) .Permit(Triggers.WaitingForTrigger, ArmStateMachineStates.States.WaitingForTrigger) .Permit(Triggers.WaitingForInterval, ArmStateMachineStates.States.WaitingForInterval) .Permit(Triggers.Recording, ArmStateMachineStates.States.Recording) .PermitReentry(Triggers.Rearming); //--------------------Disarmed----------------- overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.Disarmed) .OnEntryFrom(DisarmTrigger, o => SetOverallStatus(o)) .Permit(Triggers.DASNotFound, ArmStateMachineStates.States.CheckingForDAS) .Permit(Triggers.NoDataToDownload, ArmStateMachineStates.States.IDLE) .Permit(Triggers.ReadyForDownload, ArmStateMachineStates.States.IDLE) .Permit(Triggers.DataNeverDownloaded, ArmStateMachineStates.States.IDLE) .Permit(Triggers.FlashClear, ArmStateMachineStates.States.ClearingFlash); //--------------------PostTestProcessing----------------- overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.PostTestProcessing) .OnEntryFrom(DoneRecordingTrigger, o => SetOverallStatus(o)) .Permit(Triggers.GettingEventInfo, ArmStateMachineStates.States.GettingEventInfo) .PermitReentry(Triggers.PostTestProcessing); //--------------------CheckingForData----------------- overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.CheckingForData) .OnEntryFrom(DoneRecordingTrigger, o => SetOverallStatus(o)) .OnEntryFrom(CheckingForDataTrigger, o => SetOverallStatus(o)) .Permit(Triggers.GettingEventInfo, ArmStateMachineStates.States.GettingEventInfo) .PermitReentry(Triggers.DoneRecording) .PermitReentry(Triggers.CheckingForData); //--------------------GettingEventInfo----------------- overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.GettingEventInfo) .OnEntryFrom(GettingEventInfoTrigger, o => SetOverallStatus(o)) .OnEntryFrom(DataNeverDownloadedTrigger, o => SetOverallStatus(o)) .Permit(Triggers.DataNeverDownloaded, ArmStateMachineStates.States.ReadyForDownload); //--------------------ReadyForDownload----------------- overallArmStatusStateMachine.Configure(ArmStateMachineStates.States.ReadyForDownload) .OnEntryFrom(DataNeverDownloadedTrigger, o => SetOverallStatus(o)) .OnEntryFrom(ReadyForDownloadTrigger, o => SetOverallStatus(o)) .OnEntryFrom(FlashClearTrigger, o => SetOverallStatus(o)) .OnEntryFrom(WaitingForTriggerTrigger, o => SetOverallStatus(o)) //In case Flash Clear finishes very quickly .OnEntryFrom(WaitingForScheduleTrigger, o => SetOverallStatus(o)) .OnEntryFrom(WaitingForIntervalTrigger, o => SetOverallStatus(o)) .Permit(Triggers.DASNotFound, ArmStateMachineStates.States.IDLE) .Permit(Triggers.Downloading, ArmStateMachineStates.States.Downloading) .Permit(Triggers.FlashClear, ArmStateMachineStates.States.ClearingFlash) .Permit(Triggers.WaitingForTrigger, ArmStateMachineStates.States.WaitingForTrigger) .Permit(Triggers.WaitingForSchedule, ArmStateMachineStates.States.WaitingForSchedule) .Permit(Triggers.WaitingForInterval, ArmStateMachineStates.States.WaitingForInterval) .Ignore(Triggers.DataNeverDownloaded) .PermitReentry(Triggers.ReadyForDownload); string graph = Stateless.Graph.UmlDotGraph.Format(overallArmStatusStateMachine.GetInfo()); graph = graph.Replace("DTS.DASLib.Service.StateMachine.", ""); } public delegate void OverallStatusStateChangeDelegate(ArmStateMachineStates.States previousState, ArmStateMachineStates.States nextState); /// /// Handler for consumers to be notified when overall state transitions /// public event OverallStatusStateChangeDelegate OverallStatusStateChange; /// /// Display a message in the Global Status field. /// /// private void SetOverallStatus(ArmStateMachineStates.States newState) { if (newState != CurrentOverallStatusState) { APILogger.Log($"Transitioning from {CurrentOverallStatusState} to {newState}"); OverallStatusStateChange?.Invoke(CurrentOverallStatusState, newState); CurrentOverallStatusState = newState; } } public ArmStateMachineStates.States GetDASStatus() { return CurrentOverallStatusState; } public void FireTrigger(Triggers trigger, ArmStateMachineStates.States state) { try { //why specify state here? shouldn't that be done based on current state/trigger? switch (trigger) { case Triggers.DASNotFound: overallArmStatusStateMachine.Fire(DASNotFoundTrigger, state); break; case Triggers.NoDataToDownload: overallArmStatusStateMachine.Fire(NoDataToDownloadTrigger, state); break; case Triggers.DataNeverDownloaded: overallArmStatusStateMachine.Fire(DataNeverDownloadedTrigger, state); break; case Triggers.DoneRecording: overallArmStatusStateMachine.Fire(DoneRecordingTrigger, state); break; case Triggers.FlashClear: overallArmStatusStateMachine.Fire(FlashClearTrigger, state); break; case Triggers.WaitingForTrigger: overallArmStatusStateMachine.Fire(WaitingForTriggerTrigger, state); break; case Triggers.WaitingForSchedule: overallArmStatusStateMachine.Fire(WaitingForScheduleTrigger, state); break; case Triggers.WaitingForInterval: overallArmStatusStateMachine.Fire(WaitingForIntervalTrigger, state); break; case Triggers.Recording: overallArmStatusStateMachine.Fire(RecordingTrigger, state); break; case Triggers.PostTestProcessing: overallArmStatusStateMachine.Fire(DoneRecordingTrigger, state); break; case Triggers.CheckingForData: overallArmStatusStateMachine.Fire(CheckingForDataTrigger, state); break; case Triggers.GettingEventInfo: overallArmStatusStateMachine.Fire(GettingEventInfoTrigger, state); break; case Triggers.ReadyForDownload: overallArmStatusStateMachine.Fire(ReadyForDownloadTrigger, state); break; case Triggers.Error: overallArmStatusStateMachine.Fire(ErrorTrigger, state); break; case Triggers.Streaming: overallArmStatusStateMachine.Fire(StreamingTrigger, state); break; case Triggers.Disarm: overallArmStatusStateMachine.Fire(DisarmTrigger, state); break; case Triggers.Rearming: overallArmStatusStateMachine.Fire(RearmingTrigger, state); break; default: break; } } catch (Exception ex) { APILogger.Log(ex.Message); } } } }