/// <summary> /// Performs a dynamic transition; i.e., the transition path is determined on the fly and not recorded. /// </summary> /// <param name="targetState">The <see cref="QState"/> to transition to.</param> protected void TransitionTo(QState targetState) { Debug.Assert(targetState != s_TopState); // can't target 'top' state ExitUpToSourceState(); // This is a dynamic transition. We pass in null instead of a recorder TransitionFromSourceToTarget(targetState, null); }
/// <summary> /// DispatchException (see def on IQHsm) /// </summary> protected virtual void DoDispatchException(IQHsm hsm, Exception ex, QState state, IQEvent ev) { if (OnDispatchException(hsm, ex, state, ev)) { RaiseDispatchException(DispatchException, hsm, ex, state, ev); } }
public DispatchExceptionFailureEventArgs(Exception ex, IQHsm hsm, QState state, IQEvent ev) { _Exception = ex; _Hsm = hsm; _State = state; _OriginalEvent = ev; }
private void TransitionDownToTargetState( QState targetState, ArrayList statesTargetToLCA, int indexFirstStateToEnter, TransitionChainRecorder recorder) { // we enter the states in the passed in array in reverse order for (int stateIndex = indexFirstStateToEnter; stateIndex >= 0; stateIndex--) { Trigger((QState)statesTargetToLCA[stateIndex], QSignals.Entry, recorder); } m_MyState = targetState; // At last we are ready to initialize the target state. // If the specified target state handles init then the effective // target state is deeper than the target state specified in // the transition. while (Trigger(targetState, QSignals.Init, recorder) == null) { // Initial transition must be one level deep Debug.Assert(targetState == GetSuperState(m_MyState)); targetState = m_MyState; Trigger(targetState, QSignals.Entry, recorder); } if (recorder != null) { // We always make sure that the last entry in the recorder represents the entry to the target state. EnsureLastTransistionStepIsEntryIntoTargetState(targetState, recorder); Debug.Assert(recorder.GetRecordedTransitionChain().Length > 0); } }
private void TransitionToSynchronized(QState targetState, ref TransitionChain transitionChain) { //The entire method had been embedded within [MethodImpl(MethodImplOptions.Synchronized)], //which is not available in .NET Core, and so a lock is used instead... lock (this) { if (transitionChain != null) { // We encountered a race condition. The first (non-synchronized) check indicated that the transition chain // is null. However, a second threat beat us in getting into this synchronized method and populated // the transition chain in the meantime. We can execute the regular method again now. TransitionTo(targetState, ref transitionChain); } else { // The transition chain is not initialized yet, we need to dynamically retrieve // the required transition steps and record them so that we can subsequently simply // play them back. TransitionChainRecorder recorder = new TransitionChainRecorder(); TransitionFromSourceToTarget(targetState.GetMethodInfo(), recorder); // We pass the recorded transition steps back to the caller: transitionChain = recorder.GetRecordedTransitionChain(); } } }
protected void DoUnhandledTransition(IQHsm hsm, QState state, IQEvent qEvent) { if (OnUnhandledTransition(hsm, state, qEvent)) { RaiseUnhandledTransition(UnhandledTransition, hsm, state, qEvent); } }
protected virtual void LogRestored() { Delegate stateDelegate = Delegate.CreateDelegate(typeof(QStateDelegate), this, CurrentState.Name); QState currentState = new QState(this, (QStateDelegate)stateDelegate, CurrentState.Name); LogStateEvent(StateLogType.Restored, currentState); }
/// <summary> /// Handles the transition from the source state to the target state without the help of a previously /// recorded transition chain. /// </summary> /// <param name="targetState">The <see cref="QState"/> representing the state to transition to.</param> /// <param name="recorder">An instance of <see cref="TransitionChainRecorder"/> or <see langword="null"/></param> /// <remarks> /// Passing in <see langword="null"/> as the recorder means that we deal with a dynamic transition. /// If an actual instance of <see cref="TransitionChainRecorder"/> is passed in then we deal with a static /// transition that was not recorded yet. In this case the function will record the transition steps /// as they are determined. /// </remarks> private void TransitionFromSourceToTarget(QState targetState, TransitionChainRecorder recorder) { ArrayList statesTargetToLCA; int indexFirstStateToEnter; ExitUpToLCA(targetState, out statesTargetToLCA, out indexFirstStateToEnter, recorder); TransitionDownToTargetState(targetState, statesTargetToLCA, indexFirstStateToEnter, recorder); }
public void LogStateEvent(StateLogType logType, QState state) { LogStateEventArgs logEvent = new LogStateEventArgs(); logEvent.LogType = logType; logEvent.State = state; DoStateChange(logEvent); }
public void DoFinalStateReached(ILQHsm hsm, QState state) { if (OnFinalStateReached(hsm, state)) { LogStateEvent(StateLogType.Final, state); RaiseFinalStateReached(FinalStateReached, hsm, state); } }
public void LogStateEvent(StateLogType logType, QState state, string action) { LogStateEventArgs logEvent = new LogStateEventArgs(); logEvent.LogType = logType; logEvent.State = state; logEvent.LogText = action; DoStateChange(logEvent); }
public void LogStateEvent(StateLogType logType, QState state, QState initState) { System.Diagnostics.Debug.Assert(logType == StateLogType.Init); LogStateEventArgs logEvent = new LogStateEventArgs(); logEvent.LogType = logType; logEvent.State = state; logEvent.NextState = initState; DoStateChange(logEvent); }
public virtual void RaiseFinalStateReached(EventHandler handler, ILQHsm hsm, QState state) { if (handler != null) { LogStateEventArgs logEvent = new LogStateEventArgs(); logEvent.LogType = StateLogType.Final; logEvent.State = state; handler(hsm, logEvent); } }
/// <summary> /// Sends the specified signal to the specified state and (optionally) records the transition /// </summary> /// <param name="receiverState">The <see cref="QState"/> that represents the state method /// to which to send the signal.</param> /// <param name="qSignal">The <see cref="QSignals"/> to send.</param> /// <param name="recorder">An instance of <see cref="TransitionChainRecorder"/> if the transition /// is to be recorded; <see langword="null"/> otherwise.</param> /// <returns>The <see cref="QState"/> returned by the state that recieved the signal.</returns> /// <remarks> /// Even if a recorder is specified, the transition will only be recorded if the state /// <see paramref="receiverState"/> actually handled it. /// This function is used to record the transition chain for a static transition that is executed /// the first time. /// </remarks> private QState Trigger(QState receiverState, string qSignal, TransitionChainRecorder recorder) { QState state = Trigger(receiverState, qSignal); if ((state == null) && (recorder != null)) { // The receiverState handled the event recorder.Record(receiverState, qSignal); } return(state); }
public void PreInit() { _startState = TopState; if (_hsmS.StateMachineInfo.Name != null) { _name = _hsmS.StateMachineInfo.Name; } GQHSMManager.Instance.RegisterHsm(this); if (States != null) { foreach (GQHSMState gs in States) { gs.PreInit(this); if (gs.IsStartState) { _startState = gs.GetStateHandler(); } } } if (Transitions != null) { foreach (GQHSMTransition gt in Transitions) { gt.PreInit(this); } } if (Components != null) { foreach (GQHSMComponent gc in Components) { gc.PreInit(this); } } if (PortLinks != null) { foreach (GQHSMPortLink gpl in PortLinks) { gpl.PreInit(this); } } if (Ports != null) { foreach (GQHSMPort gp in Ports) { gp.PreInit(this); } } }
public void LogStateEvent(StateLogType logType, QState state, QState toState, string eventName, string eventDescription) { LogStateEventArgs logEvent = new LogStateEventArgs(); logEvent.LogType = logType; logEvent.State = state; logEvent.NextState = toState; logEvent.EventName = eventName; logEvent.EventDescription = eventDescription; DoStateChange(logEvent); }
///<summary> /// Retrieves the super state (parent state) of the specified /// state by sending it the empty signal. ///</summary> private MethodInfo GetSuperStateMethod(MethodInfo stateMethod) { QState superState = (QState)stateMethod.Invoke(this, new object[] { new QEvent((int)QSignals.Empty) }); if (superState != null) { return(superState.GetMethodInfo()); } else { return(null); } }
private QState Trigger(QState state, string qSignal) { QState newState = (QState)state.Method.Invoke(state.calleeObject, new object[] { (IQEvent) new QEvent(qSignal) }); if (newState == null) { return(null); } else { return(newState); } }
/// <summary> /// Determines whether the state machine is in the state specified by <see paramref="inquiredState"/>. /// </summary> /// <param name="inquiredState">The state to check for.</param> /// <returns> /// <see langword="true"/> if the state machine is in the specified state; /// <see langword="false"/> otherwise. /// </returns> /// <remarks> /// If the currently active state of a hierarchical state machine is s then it is in the /// state s AND all its parent states. /// </remarks> public bool IsInState(QState inquiredState) { MethodInfo stateMethod; for (stateMethod = m_MyStateMethod; stateMethod != null; stateMethod = GetSuperStateMethod(stateMethod)) { if (stateMethod == inquiredState.GetMethodInfo()) // do the states match? { return(true); } } return(false); // no match found }
/// <summary> /// Determines whether the state machine is in the state specified by <see paramref="inquiredState"/>. /// </summary> /// <param name="inquiredState">The state to check for.</param> /// <returns> /// <see langword="true"/> if the state machine is in the specified state; /// <see langword="false"/> otherwise. /// </returns> /// <remarks> /// If the currently active state of a hierarchical state machine is s then it is in the /// state s AND all its parent states. /// </remarks> public bool IsInState(QState inquiredState) { QState state; for (state = m_MyState; state != null; state = GetSuperState(state)) { if (state == inquiredState) // do the states match? { return(true); } } return(false); // no match found }
protected void ComplainIfUnhandled(QState state, IQEvent qEvent) { switch (qEvent.QSignal) { case QSignals.Init: case QSignals.Entry: case QSignals.Exit: case QSignals.Empty: break; default: DoUnhandledTransition(this, state, qEvent); break; } }
/// <summary> /// Do a internal transition to another state using signalName /// </summary> /// <returns> /// true if handled /// </returns> /// <param name='signalName'> /// The name of the signal that will transition to another state /// </param> /// <param name='data'> /// any object that is passed between states /// </param> public bool StateTransitionInternal(string stateName, GQHSMParameters Params, string signalName) { GQHSMTransition transition = null; string fullTransitionName = stateName + "." + signalName; // if we know about the transition bool retVal = false; retVal = GetGuardedTransition(fullTransitionName, Params, ref transition); if (transition != null) { GQHSMState toState = GetState(transition.GetDestinationStateID()); GQHSMState fromState = GetState(transition.GetSourceStateID()); QState stateHandler = GetTopState(); if (toState != null) { stateHandler = toState.GetStateHandler(); } if (_instrument && !transition.DoNotInstrument) { LogStateEvent(StateLogType.EventTransition, GetCurrentState(), stateHandler, transition.Name, signalName); } if (!transition.IsInnerTransition) { DoTransitionTo(stateHandler, transition.GetSlot()); } // still execute actions on this inner transition transition.InvokeActions(); retVal = true; } else if (signalName == "Internal.TransitionTo") { if (Params.Count == 1) { GQHSMState state = (GQHSMState)Params[0].Value; DoTransitionTo(state.GetStateHandler()); return(true); } return(false); } return(retVal); }
/// <summary> /// Get a QState delegate for a particular state /// </summary> /// <param name="Id"></param> /// <returns></returns> public QState GetStateHandler(Guid Id) { QState returnState = GetTopState(); GQHSMState foundState; if (Id != Guid.Empty) { foundState = GetState(Id); if (foundState != null) { returnState = foundState.GetStateHandler(); } } return(returnState); }
private MethodInfo Trigger(MethodInfo stateMethod, QSignals qSignal) { var evt = new QEvent((int)qSignal); OnEvent(stateMethod, evt); QState state = (QState)stateMethod.Invoke(this, new object[] { evt }); if (state == null) { return(null); } else { return(state.GetMethodInfo()); } }
/// <summary> /// Performs the transition from the current state to the specified target state. /// </summary> /// <param name="targetState">The <see cref="QState"/> to transition to.</param> /// <param name="transitionChain">A <see cref="TransitionChain"/> used to hold the transition chain that /// needs to be executed to perform the transition to the target state.</param> /// <remarks> /// The very first time that a given static transition is executed, the <see paramref="transitionChain"/> /// reference will point to <see langword="null"/>. In this case a new <see cref="TransitionChain"/> /// instance is created. As the complete transition is performed the individual transition steps are /// recorded in the new <see cref="TransitionChain"/> instance. At the end of the call the new /// (and now filled) <see cref="TransitionChain"/> is handed back to the caller. /// If the same transition needs to be performed later again, the caller needs to pass /// in the filled <see cref="TransitionChain"/> instance. The recorded transition path will then be /// played back very efficiently. /// </remarks> protected void TransitionTo(QState targetState, ref TransitionChain transitionChain) { Debug.Assert(targetState != s_TopState); // can't target 'top' state ExitUpToSourceState(); if (transitionChain == null) // for efficiency the first check is not thread-safe { // We implement the double-checked locking pattern TransitionToSynchronized(targetState, ref transitionChain); } else { // We just need to 'replay' the transition chain that is stored in the transitions chain. ExecuteTransitionChain(transitionChain); } }
///<summary> /// Retrieves the super state (parent state) of the specified /// state by sending it the empty signal. ///</summary> private QState GetSuperState(QState state) { QState superState; // don't care what type of object takes the method invocation superState = (QState)state.Method.Invoke(state.calleeObject, new object[] { new QEvent(QSignals.Empty) }); if (superState != null) { return(superState); } else { return(null); } }
private void ExecuteTransitionChain(TransitionChain transitionChain) { // There must always be at least one transition step in the provided transition chain Debug.Assert(transitionChain.Length > 0); TransitionStep transitionStep = transitionChain[0]; // to shut up the compiler; // without it we would get the following error on the line // m_MyState = transitionStep.State; // at the end of this method: Use of possibly unassigned field 'State' for (int i = 0; i < transitionChain.Length; i++) { transitionStep = transitionChain[i]; Trigger(transitionStep.State, transitionStep.QSignal); } m_MyState = transitionStep.State; }
public override void PreInit(GQHSM parentHSM) { base.PreInit(parentHSM); _fullName = _parentHSM.RegisterState(this); if (ChildStates != null) { foreach (GQHSMState gs in ChildStates) { gs.PreInit(parentHSM); if (gs.IsStartState) { _childStartState = gs; } } } _stateHandler = new QState(this, StateHandler, Name); }
/// <summary> /// Dispatches the specified event to this state machine /// </summary> /// <param name="qEvent">The <see cref="IQEvent"/> to dispatch.</param> protected void CoreDispatch(IQEvent qEvent) { // We let the event bubble up the chain until it is handled by a state handler m_MySourceStateMethod = m_MyStateMethod; do { OnEvent(m_MySourceStateMethod, qEvent); QState state = (QState)m_MySourceStateMethod.Invoke(this, new object[] { qEvent }); if (state != null) { m_MySourceStateMethod = state.GetMethodInfo(); } else { m_MySourceStateMethod = null; } } while (m_MySourceStateMethod != null); }
private void ExitUpToSourceState() { for (QState state = m_MyState; state != m_MySourceState;) { Debug.Assert(state != null); QState stateToHandleExit = Trigger(state, QSignals.Exit); if (stateToHandleExit != null) { // state did not handle the Exit signal itself state = stateToHandleExit; } else { // state handled the Exit signal. We need to elicit // the superstate explicitly. state = GetSuperState(state); } } }