///// <summary> ///// Provides a mechanism to stop the finite state machine. ///// It will cause the method <see cref="RunStateMachine()"/> to complete so that the thread in which it runs can stop too. ///// ///// Note that for finite state machine designs that raise events in the event handlers, ///// you must have a Stopping event handler as part of your state machine design. ///// The code in the Stopping event must not raise any events and Stop() should be called from within that handler. ///// </summary> //public void Stop() //{ // string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name; // if (log.IsDebugEnabled) // log.Debug($"{methodName}: enter"); // stopRequested = true; // lock (locker) // { // Monitor.Pulse(locker); // Wakes up the state machine thread if it is sleeping. // } // if (log.IsDebugEnabled) // log.Debug($"{methodName}: exit"); //} /// <summary> /// Sets the current state of the finite state machine. /// </summary> /// <param name="toState">The finite state that we want to become the current state.</param> /// <exception cref="ArgumentException">Thrown if the parameter toState is a finite state that has not been added by <see cref="AddState(FiniteState)"/></exception> public void SetCurrentState(FiniteState toState) { string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name; if (log.IsDebugEnabled) { log.Debug($"{methodName}: enter"); } if (!ManagedStates.TryGetValue(toState.Name, out FiniteState currentStateCandidate)) { throw new ArgumentException($"Attempted to set current state to '{toState.Name}' but no state of that name is managed by this state machine."); } CurrentState = currentStateCandidate; if (log.IsInfoEnabled) { log.Info($"{methodName}: changed to [{CurrentState.Name}]"); } if (log.IsDebugEnabled) { log.Debug($"{methodName}: exit"); } }
/// <summary> /// Add a new FiniteState to the collection of states managed by this state machine. /// </summary> /// <param name="StateToAdd">The finite state to add.</param> /// <returns>A reference to the finite state that was just added.</returns> /// <exception cref="ArgumentException">Thrown if you try to add a finite state that has already been added.</exception> public FiniteState AddState(FiniteState StateToAdd) { string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name; try { if (log.IsDebugEnabled) { log.Debug($"{methodName}: enter"); } if (ManagedStates.ContainsKey(StateToAdd.Name)) { throw new ArgumentException($"Attempt to add a duplicate state '{StateToAdd.Name}'."); } if (log.IsInfoEnabled) { log.Info($"{methodName}: [{StateToAdd.Name}]"); } ManagedStates.Add(StateToAdd.Name, StateToAdd); return(StateToAdd); } finally { if (log.IsDebugEnabled) { log.Debug($"{methodName}: exit"); } } }
/// <summary> /// Starts the state machine. /// /// Every state diagram has a start state with a single transition to some initial state in the diagram via a start event. /// This method performs the following actions: /// * creates the start state /// * creates the start event /// * adds a transition from the start state, via the start event to InitialState, the finite state passed as a parameter /// * sets the current state to be the start state /// * raises the start event /// The OnEntry event handler for InitialState will be executed. /// The state machine is now sitting in it's initial state and waiting for an event to occur. /// </summary> /// <param name="InitialState">The finite state in which this state machine starts.</param> public void Start(FiniteState InitialState) { string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name; if (log.IsDebugEnabled) { log.Debug($"{methodName}: enter"); } engine.Start(InitialState); if (log.IsDebugEnabled) { log.Debug($"{methodName}: exit"); } }
/// <summary> /// Create and add a new FiniteState to the collection of states managed by this state machine. /// </summary> /// <param name="Name">The name finite state to create and add.</param> /// <returns>A reference to the finite state that was just created and added.</returns> /// <exception cref="ArgumentException">Thrown if you try to add a finite state that has already been added.</exception> public FiniteState AddState(string Name) { string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name; try { if (log.IsDebugEnabled) { log.Debug($"{methodName}: enter"); } FiniteState stateToAdd = new FiniteState(Name); return(engine.AddState(stateToAdd)); } finally { if (log.IsDebugEnabled) { log.Debug($"{methodName}: exit"); } } }
/// <summary> /// Starts the state machine. /// /// Every state diagram has a start state with a single transition to some initial state in the diagram via a start event. /// This method performs the following actions: /// * creates the start state /// * creates the start event /// * adds a transition from the start state, via the start event to InitialState, the finite state passed as a parameter /// * sets the current state to be the start state /// * raises the start event /// The OnEntry event handler for InitialState will be executed. /// The state machine is now sitting in it's initial state and waiting for an event to occur. /// /// On a technical note, the underlying Thread, in which the event handlers are run, is also created and started here. /// </summary> /// <param name="InitialState">The finite state in which this state machine starts.</param> /// <exception cref="ArgumentException">Thrown if the parameter InitialState is a finite state that has not been added by <see cref="AddState(FiniteState)"/></exception> public void Start(FiniteState InitialState) { string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name; if (log.IsDebugEnabled) { log.Debug($"{methodName}: enter"); } //if (OnExceptionAction == null) //{ // throw new ArgumentException($"The state machine must have an OnExceptionAction before you can start it."); //} // // Perform sanity checks // foreach (KeyValuePair <string, FiniteState> kvp in ManagedStates) { // // 1. Make sure each finite state has an OnEnterAction // FiniteState finiteState = kvp.Value; if (finiteState.OnEnterAction == null) { throw new Exception($"The finite state, '{finiteState.Name}' does not have an OnEnterAction."); } // // 2. Make sure the target state in every transition has been added to the state machine. // foreach (KeyValuePair <string, FiniteStateTransition> transitionKvp in finiteState.Transitions) { FiniteStateTransition fst = transitionKvp.Value; string stateName = fst.ToState.Name; if (!ManagedStates.ContainsKey(stateName)) { throw new Exception($"The finite state, '{stateName}' has not been added to the state machine."); } } } FiniteState startState = new FiniteState(START_STATE_NAME); FiniteStateEvent startEvent = new FiniteStateEvent(START_EVENT_NAME); startState.OnEnterAction = () => { }; // needs an empty handler AddState(startState); startState.AddTransition(startEvent, InitialState); SetCurrentState(startState); RaiseEvent(startEvent); //Thread runner = new Thread(RunStateMachine) //{ // Name = Name //}; //runner.Start(); if (log.IsDebugEnabled) { log.Debug($"{methodName}: exit"); } }
/// <summary> /// Add a new transition to the collection of transitions from this state that is created from an event and a state. /// </summary> /// <param name="ViaEvent">The event that will trigger this transition.</param> /// <param name="ToState">The state that is the destination of the transition.</param> /// <exception cref="ArgumentException">Thrown if the event in TransitionToAdd has already been used in a transition from this state.</exception> public void AddTransition(FiniteStateEvent ViaEvent, FiniteState ToState) { AddTransition(new FiniteStateTransition(ViaEvent, ToState)); }
public void start(FiniteState startState) { engine.Start(startState); }