/// <summary> /// Re-routes a transition between a specified source and destination /// </summary> /// <param name="transition">The transition to re-route.</param> /// <param name="source">The new source for the transition.</param> /// <param name="target">The new target for the transition.</param> /// <remarks> /// This method can be used when extending state machines. /// Careful design consideration should be made before using this method. /// Never change a state machines structure while it is running. /// </remarks> protected void rerouteTransition(NSFTransition transition, NSFState source, NSFState target) { transition.Source.removeOutgoingTransition(transition); transition.Target.removeIncomingTransition(transition); transition.Source = source; transition.Target = target; }
/// <summary> /// Determines if the queuing the an event causes a state to enter before defaultWaitTime elapses. /// </summary> /// <param name="eventToInject">The event to queue.</param> /// <param name="stateToWaitFor">The state to wait for.</param> /// <param name="waitTime">The time in ms to wait for the stateToWaitFor to enter.</param> /// <returns> /// True if the stateToWaitFor is entered. /// False if the stateToWaitFor is not entered before time expires. /// </returns> /// <remarks> /// This is a blocking call, the caller may be blocked for as long as waitTime. /// </remarks> public bool doesEventResultInState(NSFEvent eventToInject, NSFState stateToWaitFor, int waitTime) { firstSignal.clear(); stateToWaitFor.EntryActions += firstSignal.send; if (eventToInject != null) { eventToInject.queueEvent(); } if (stateToWaitFor.isActive()) { stateToWaitFor.EntryActions -= firstSignal.send; return true; } if (!firstSignal.wait(waitTime)) { stateToWaitFor.EntryActions -= firstSignal.send; return false; } stateToWaitFor.EntryActions -= firstSignal.send; return true; }
/// <summary> /// Creates a state machine context. /// </summary> /// <param name="source">The state machine.</param> /// <param name="enteringState">The state being entered.</param> /// <param name="exitingState">The state being exited.</param> /// <param name="transition">The associated transition.</param> /// <param name="trigger">The triggering event.</param> public NSFStateMachineContext(NSFStateMachine source, NSFState enteringState, NSFState exitingState, NSFTransition transition, NSFEvent trigger) : base(source) { EnteringState = enteringState; ExitingState = exitingState; Transition = transition; Trigger = trigger; }
/// <summary> /// Indicates if the region's active substate is the specified state. /// </summary> /// <param name="state">The state in question.</param> /// <returns>True if the region's active substate is the specified state, false otherwise.</returns> public bool isInState(NSFState state) { if (!active) { return(false); } return(activeSubstate.isInState(state)); }
/// <summary> /// Indicates if the specified state is active, i.e. is "in" the specified state. /// </summary> /// <param name="state">State in question.</param> /// <returns>True if the specified state is active, otherwise false.</returns> public virtual bool isInState(NSFState state) { if (!active) { return(false); } return(this == state); }
/// <summary> /// Sets the region's active substate. /// </summary> /// <param name="substate">The new active substate.</param> internal void setActiveSubstate(NSFState substate) { // Set history substate to the current, active substate whenever the active substate is about to becomes the null state, // except that the history substate should not be set to the null state or the initial state. if ((substate == NSFState.NullState) && (activeSubstate != NSFState.NullState) && (activeSubstate != initialState)) { historySubstate = activeSubstate; } activeSubstate = substate; }
/// <summary> /// Creates a local transition. /// </summary> /// <param name="name">User assigned name for transition.</param> /// <param name="source">Transition source.</param> /// <param name="target">Transition target.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> public NSFLocalTransition(NSFString name, NSFCompositeState source, NSFState target, NSFEvent trigger, NSFBoolGuard <NSFStateMachineContext> guard, NSFVoidAction <NSFStateMachineContext> action) : base(name, source, target, trigger, guard, action) { compositeSource = source; // Target must be substate of source or the source itself if ((!Source.isParent(Target)) && (Source != Target)) { throw new Exception(Name + " invalid local transition, source is neither parent of nor equal to target"); } Source.addOutgoingTransition(this); }
/// <summary> /// Creates a local transition. /// </summary> /// <param name="name">User assigned name for transition.</param> /// <param name="source">Transition source.</param> /// <param name="target">Transition target.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> public NSFLocalTransition(NSFString name, NSFCompositeState source, NSFState target, NSFEvent trigger, NSFBoolGuard<NSFStateMachineContext> guard, NSFVoidAction<NSFStateMachineContext> action) : base(name, source, target, trigger, guard, action) { compositeSource = source; // Target must be substate of source or the source itself if ((!Source.isParent(Target)) && (Source != Target)) { throw new Exception(Name + " invalid local transition, source is neither parent of nor equal to target"); } Source.addOutgoingTransition(this); }
protected internal override void enter(NSFStateMachineContext context, bool useHistory) { // Base class behavior base.enter(context, false); // Additional behavior // Enter history substate, using recursive history NSFState historySubstate = parentRegion.HistorySubstate; if (historySubstate != NSFState.NullState) { historySubstate.enter(context, true); } }
/// <summary> /// Indicates if this state is a parent of the specified substate. /// </summary> /// <param name="substate">The substate in question.</param> /// <returns>True if this state is a parent, false otherwise.</returns> internal bool isParent(NSFState substate) { NSFState substateParent = substate.ParentState; while (substateParent != null) { if (substateParent == this) { return(true); } else { substateParent = substateParent.ParentState; } } return(false); }
protected override void fireTransition(NSFStateMachineContext context) { Source.exit(context); // Exit parent states until common parent is found NSFState parentState = Source.ParentState; while ((parentState != null) && (!parentState.isParent(Target))) { parentState.exit(context); parentState = parentState.ParentState; } // Reset context possibly changed by exiting states context.EnteringState = null; context.ExitingState = null; Actions.execute(context); Target.enter(context, false); }
/// <summary> /// Creates a transition. /// </summary> /// <param name="name">User assigned name for transition.</param> /// <param name="source">Transition source.</param> /// <param name="target">Transition target.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> /// <remarks>Deprecated - Use NSFExternalTransition or NSFLocalTransition</remarks> protected NSFTransition(NSFString name, NSFState source, NSFState target, NSFEvent trigger, NSFBoolGuard <NSFStateMachineContext> guard, NSFVoidAction <NSFStateMachineContext> action) : base(name) { this.source = source; this.target = target; Guards += guard; Actions += action; addTrigger(trigger); // Validity check if ((source == target) && (triggers.Count == 0) && Guards.isEmpty()) { throw new Exception(Name + " invalid self-transition with no trigger or guard"); } target.addIncomingTransition(this); // Outgoing transitions must be added by concrete classes Guards.setExceptionAction(handleGuardException); Actions.setExceptionAction(handleActionException); }
/// <summary> /// Creates a transition. /// </summary> /// <param name="name">User assigned name for transition.</param> /// <param name="source">Transition source.</param> /// <param name="target">Transition target.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> /// <remarks>Deprecated - Use NSFExternalTransition or NSFLocalTransition</remarks> protected NSFTransition(NSFString name, NSFState source, NSFState target, NSFEvent trigger, NSFBoolGuard<NSFStateMachineContext> guard, NSFVoidAction<NSFStateMachineContext> action) : base(name) { this.source = source; this.target = target; Guards += guard; Actions += action; addTrigger(trigger); // Validity check if ((source == target) && (triggers.Count == 0) && Guards.isEmpty()) { throw new Exception(Name + " invalid self-transition with no trigger or guard"); } target.addIncomingTransition(this); // Outgoing transitions must be added by concrete classes Guards.setExceptionAction(handleGuardException); Actions.setExceptionAction(handleActionException); }
/// <summary> /// Adds a substate to the region's list of substates. /// </summary> /// <param name="substate">The substate to add.</param> internal void addSubstate(NSFState substate) { substates.Add(substate); // Any single state in a region can be the initial state // If more than one state exists in a region, there must be one and only one NSFInitialState // First substate is automatically registered as initial state if (substates.Count == 1) { initialState = substate; return; } // Not first state // If initial state is not already an NSFInitialState if (!(initialState is NSFInitialState)) { if (substate is NSFInitialState) { initialState = substate; } else // Not adding an NSFInitialState { // Reset initial state to null, enforcing requirement for an NSFInitialState initialState = NSFState.NullState; } } else // Initial state already established { if (substate is NSFInitialState) { throw new Exception(Name + " only one initial state allowed in a region"); } } }
public override bool isInState(NSFState state) { if (!active) { return(false); } // Base class behavior if (base.isInState(state)) { return(true); } // Check regions foreach (NSFRegion region in regions) { if (region.isInState(state)) { return(true); } } return(false); }
public override bool isInState(NSFState state) { if (!active) { return false; } // Base class behavior if (base.isInState(state)) { return true; } // Check regions foreach (NSFRegion region in regions) { if (region.isInState(state)) { return true; } } return false; }
/// <summary> /// Indicates if the region's active substate is the specified state. /// </summary> /// <param name="state">The state in question.</param> /// <returns>True if the region's active substate is the specified state, false otherwise.</returns> public bool isInState(NSFState state) { if (!active) { return false; } return activeSubstate.isInState(state); }
/// <summary> /// Resets the region to its initial condition. /// </summary> internal void reset() { active = false; activeSubstate = NSFState.NullState; historySubstate = NSFState.NullState; foreach (NSFState state in substates) { state.reset(); } }
/// <summary> /// Indicates if the specified state is active, i.e. is "in" the specified state. /// </summary> /// <param name="state">State in question.</param> /// <returns>True if the specified state is active, otherwise false.</returns> public virtual bool isInState(NSFState state) { if (!active) { return false; } return (this == state); }
/// <summary> /// Creates a local transition. /// </summary> /// <param name="source">Transition source.</param> /// <param name="target">Transition target.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> public NSFLocalTransition(NSFCompositeState source, NSFState target, NSFEvent trigger, NSFBoolGuard<NSFStateMachineContext> guard, NSFVoidAction<NSFStateMachineContext> action) : this(source.Name + "To" + target.Name, source, target, trigger, guard, action) { }
/// <summary> /// Creates a local transition. /// </summary> /// <param name="source">Transition source.</param> /// <param name="target">Transition target.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> public NSFLocalTransition(NSFCompositeState source, NSFState target, NSFEvent trigger, NSFBoolGuard <NSFStateMachineContext> guard, NSFVoidAction <NSFStateMachineContext> action) : this(source.Name + "To" + target.Name, source, target, trigger, guard, action) { }
/// <summary> /// Creates an internal transition. /// </summary> /// <param name="state">Transition state.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> /// <remarks>The default name for the transition is [state.Name]ReactionsTo[trigger.Name]</remarks> public NSFInternalTransition(NSFState state, NSFEvent trigger, NSFBoolGuard<NSFStateMachineContext> guard, NSFVoidAction<NSFStateMachineContext> action) : this(state.Name + "ReactionsTo" + trigger.Name, state, trigger, guard, action) { }
/// <summary> /// Creates an external transition. /// </summary> /// <param name="name">User assigned name for transition.</param> /// <param name="source">Transition source.</param> /// <param name="target">Transition target.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> public NSFExternalTransition(NSFString name, NSFState source, NSFState target, NSFEvent trigger, NSFBoolGuard<NSFStateMachineContext> guard, NSFVoidAction<NSFStateMachineContext> action) : base(name, source, target, trigger, guard, action) { Source.addOutgoingTransition(this); }
/// <summary> /// Determines if the queuing the an event causes a state to enter before defaultWaitTime elapses. /// </summary> /// <param name="eventToInject">The event to queue.</param> /// <param name="stateToWaitFor">The state to wait for.</param> /// <returns> /// True if the stateToWaitFor is entered. /// False if the stateToWaitFor is not entered before time expires. /// </returns> /// <remarks> /// This is a blocking call, the caller may be blocked for as long as <see cref="defaultWaitTime"/>. /// </remarks> public bool doesEventResultInState(NSFEvent eventToInject, NSFState stateToWaitFor) { return doesEventResultInState(eventToInject, stateToWaitFor, defaultWaitTime); }
/// <summary> /// Creates an internal transition. /// </summary> /// <param name="state">Transition state.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> /// <remarks>The default name for the transition is [state.Name]ReactionsTo[trigger.Name]</remarks> public NSFInternalTransition(NSFState state, NSFEvent trigger, NSFBoolGuard <NSFStateMachineContext> guard, NSFVoidAction <NSFStateMachineContext> action) : this(state.Name + "ReactionsTo" + trigger.Name, state, trigger, guard, action) { }
/// <summary> /// Indicates if this state is a parent of the specified substate. /// </summary> /// <param name="substate">The substate in question.</param> /// <returns>True if this state is a parent, false otherwise.</returns> internal bool isParent(NSFState substate) { NSFState substateParent = substate.ParentState; while (substateParent != null) { if (substateParent == this) { return true; } else { substateParent = substateParent.ParentState; } } return false; }
/// <summary> /// Creates an internal transition. /// </summary> /// <param name="name">User assigned name for transition.</param> /// <param name="state">Transition state.</param> /// <param name="trigger">Transition trigger.</param> /// <param name="guard">Transition guard.</param> /// <param name="action">Transition action.</param> public NSFInternalTransition(NSFString name, NSFState state, NSFEvent trigger, NSFBoolGuard <NSFStateMachineContext> guard, NSFVoidAction <NSFStateMachineContext> action) : base(name, state, state, trigger, guard, action) { Source.addOutgoingTransition(this); }
/// <summary> /// Determines if the queuing the an event causes two states to enter before waitTime elapses. /// </summary> /// <param name="eventToInject">The event to queue.</param> /// <param name="stateToWaitFor">The first of two states to wait for.</param> /// <param name="secondStateToWaitFor">The second of two states to wait for.</param> /// <param name="waitTime">The time in ms to wait for the each state to enter.</param> /// <returns> /// True if both states are entered. /// False if either of the states fails to enter before time expires. /// </returns> /// <remarks> /// This is a blocking call, the caller may be blocked for as long as twice waitTime. /// The states may be congruently entered. /// </remarks> public bool doesEventResultInState(NSFEvent eventToInject, NSFState stateToWaitFor, NSFState secondStateToWaitFor, int waitTime) { secondSignal.clear(); stateToWaitFor.EntryActions += secondSignal.send; secondStateToWaitFor.EntryActions += secondSignal.send; if (!doesEventResultInState(eventToInject, stateToWaitFor, waitTime)) { secondStateToWaitFor.EntryActions -= secondSignal.send; return false; } if (secondStateToWaitFor.isActive()) { secondStateToWaitFor.EntryActions -= secondSignal.send; return true; } if (!secondSignal.wait(waitTime)) { secondStateToWaitFor.EntryActions -= secondSignal.send; return false; } secondStateToWaitFor.EntryActions -= secondSignal.send; return true; }