public ChoiceStateTest(String name)
            : base(name, new NSFEventThread(name))
        {
            // Events
            evaluateEvent = new NSFEvent("EvaluateEvent", this);
            waitEvent = new NSFEvent("WaitEvent", this);

            // Regions and states, from outer to inner
            initialChoiceStateTestState = new NSFInitialState("InitialChoiceStateTest", this);
            waitToEvaluateState = new NSFCompositeState("WaitToEvaluate", this, null, null);
            evaluateValueState = new NSFChoiceState("EvaluateValue", this);
            evaluatedState = new NSFCompositeState("Evaluated", this, null, null);
            initialEvaluatedState = new NSFInitialState("InitialEvaluatedState", evaluatedState);
            valueLowState = new NSFCompositeState("ValueLow", evaluatedState, null, null);
            valueMiddleState = new NSFCompositeState("ValueMiddle", evaluatedState, null, null);
            valueHighState = new NSFCompositeState("ValueHigh", evaluatedState, null, null);

            // Transitions, ordered internal, local, external
            initialChoiceStateTestToWaitToEvaluateTransition = new NSFExternalTransition("InitialChoiceStateTestToWaitToEvaluate", initialChoiceStateTestState, waitToEvaluateState, null, null, null);
            waitToEvaluateToEvaluateValueTransition = new NSFExternalTransition("State1ToState2", waitToEvaluateState, evaluateValueState, evaluateEvent, null, null);
            //waitToEvaluateToEvaluateValueTransition = new NSFExternalTransition("State1ToState2", waitToEvaluateState, evaluatedState, evaluateEvent, null, null);
            initialEvaluatedToValueLowTransition = new NSFExternalTransition("InitialEvaluatedToValueLowTransition", initialEvaluatedState, valueLowState, null, null, null);
            evaluateValueToValueLowTransition = new NSFExternalTransition("EvaluateValueToValueLowTransition", evaluateValueState, valueLowState, null, isValueLow, null);
            evaluateValueToValueMiddleTransition = new NSFExternalTransition("EvaluateValueToValueMiddleTransition", evaluateValueState, valueMiddleState, null, Else, null);
            evaluateValueToValueHighTransition = new NSFExternalTransition("EvaluateValueToValueHighTransition", evaluateValueState, valueHighState, null, isValueHigh, null);
            evaluatedToWaitToEvaluateTransition = new NSFExternalTransition("EvaluatedToWaitToEvaluateTransition", evaluatedState, waitToEvaluateState, waitEvent, null, addValue);
        }
        private void createStateMachine()
        {
            // State Machine Components
            // Define and initialize in the order:
            //   1) Events
            //   2) Regions and states, from outer to inner
            //   3) Transitions, ordered internal, local, external
            //   4) Group states and transitions within a region together.

            // Events
            commReadyEvent = new NSFEvent("CommReady", this);
            hardwareResetEvent = new NSFEvent("HardwareReset", this);

            // Regions and states, from outer to inner 
            // Initial state construtors take the form (name, parent)
            initialResetStrategyState = new NSFInitialState("InitialResetStrategy", this);
            // Composite state construtors take the form (name, parent, entry action, exit action)
            resetHardwareState = new NSFCompositeState("ResetHardware", this, resetHardwareEntryActions, null);
            reestablishCommunicationsState = new NSFCompositeState("ReestablishCommunications", this, reestablishCommunicationsEntryActions, null);
            readyState = new NSFCompositeState("ThreadReady", this, null, null);

            // Transitions, ordered internal, local, external
            // External transition construtors take the form (name, source, target, trigger, guard, action)
            initialResetStrategyToResetHardwareTransition = new NSFExternalTransition("InitialToResetHardware", initialResetStrategyState, resetHardwareState, null, null, resetVariables);
            resetHardwareToReestablishCommunicationsTransition = new NSFExternalTransition("ResetHardwareToReestablishCommunications", resetHardwareState, reestablishCommunicationsState, null, isHardwareReset, null);
            reestablishCommunicationsStateToReadyTransition = new NSFExternalTransition("ReestablishCommunicationsStateToReady", reestablishCommunicationsState, readyState, null, isCommReady, null);

            // Actions
            resetHardwareAction = new NSFScheduledAction("ReadHardware", resetHardware, EventThread);
            readyCommAction = new NSFScheduledAction("ResetComm", resetComm, EventThread);
        }
        protected internal override NSFEventStatus processEvent(NSFEvent nsfEvent)
        {
            NSFTransition elseTransition = null;

            // Check transitions out of state
            foreach (NSFTransition transition in outgoingTransitions)
            {
                if (!transition.Guards.isEmpty())
                {
                    if (transition.processEvent(nsfEvent) == NSFEventStatus.NSFEventHandled)
                    {
                        return(NSFEventStatus.NSFEventHandled);
                    }
                }
                else
                {
                    if (elseTransition != null)
                    {
                        // A choice is ill formed if it has more than one "else" transition
                        throw new Exception(Name + " invalid choice state with multiple else transitions");
                    }

                    elseTransition = transition;
                }
            }

            if ((elseTransition != null) && (elseTransition.processEvent(nsfEvent) == NSFEventStatus.NSFEventHandled))
            {
                return(NSFEventStatus.NSFEventHandled);
            }

            // If no transition is taken, then the model is ill formed and an exception is thrown.
            throw new Exception(Name + " invalid model with no transition taken from a choice state");
        }
Example #4
0
        /// <summary>
        /// Creates a deep copy.
        /// </summary>
        /// <param name="name">The new name for the copy.</param>
        /// <returns>A copy of the event.</returns>
        /// <remarks>
        /// A common design pattern is to queue data event copies, each with its own unique data payload, to state machines for handling.
        /// </remarks>
        public NSFEvent copy(NSFString name)
        {
            NSFEvent eventCopy = copy();

            eventCopy.Name = name;
            return(eventCopy);
        }
        protected internal override NSFEventStatus processEvent(NSFEvent nsfEvent)
        {
            // Check if all incoming transitions are satisfied
            bool incomingTransitionsSatisfied = true;

            foreach (NSFTransition incomingTransition in incomingTransitions)
            {
                if (!completedTransitions.Contains(incomingTransition))
                {
                    incomingTransitionsSatisfied = false;
                    break;
                }
            }

            if (incomingTransitionsSatisfied)
            {
                // Take all outgoing transitions
                foreach (NSFTransition outgoingTransition in outgoingTransitions)
                {
                    // All outgoing transitions must be null transitions by UML2.x standard
                    outgoingTransition.processEvent(nsfEvent);
                }

                return(NSFEventStatus.NSFEventHandled);
            }

            return(NSFEventStatus.NSFEventUnhandled);
        }
        /// <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;
        }
Example #7
0
        /// <summary>
        /// Performs common construction behaviors.
        /// </summary>
        /// <param name="thread">The state machine's thread.</param>
        private void construct(NSFEventThread thread)
        {
            ConsecutiveLoopDetectionEnabled = true;
            ConsecutiveLoopLimit            = 1000;
            EventLimitDetectionEnabled      = true;
            EventLimit        = 100;
            EventThread       = thread;
            QueuedEvents      = 0;
            LoggingEnabled    = true;
            RunStatus         = NSFEventHandlerRunStatus.EventHandlerStopped;
            TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerReady;

            resetEvent           = new NSFEvent("Reset", this);
            runToCompletionEvent = new NSFEvent("RunToCompletion", this);
            startEvent           = new NSFEvent("Start", this);
            stopEvent            = new NSFEvent("Stop", this);
            terminateEvent       = new NSFEvent("Terminate", this);

            StateChangeActions.setExceptionAction(handleStateChangeActionException);

            if (isTopStateMachine())
            {
                EventThread.addEventHandler(this);
            }
        }
        protected internal override NSFEventStatus processEvent(NSFEvent nsfEvent)
        {
            // Additional behavior

            // Let regions process event first
            NSFEventStatus eventStatus = NSFEventStatus.NSFEventUnhandled;

            foreach (NSFRegion region in regions)
            {
                NSFEventStatus status = region.processEvent(nsfEvent);

                if (status == NSFEventStatus.NSFEventHandled)
                {
                    eventStatus = NSFEventStatus.NSFEventHandled;
                }
            }

            if (eventStatus == NSFEventStatus.NSFEventHandled)
            {
                return(NSFEventStatus.NSFEventHandled);
            }

            // Base class behavior
            return(base.processEvent(nsfEvent));
        }
        protected internal override NSFEventStatus processEvent(NSFEvent nsfEvent)
        {
            NSFTransition elseTransition = null;

            // Check transitions out of state
            foreach (NSFTransition transition in outgoingTransitions)
            {
                if (!transition.Guards.isEmpty())
                {
                    if (transition.processEvent(nsfEvent) == NSFEventStatus.NSFEventHandled)
                    {
                        return NSFEventStatus.NSFEventHandled;
                    }
                }
                else
                {
                    if (elseTransition != null)
                    {
                        // A choice is ill formed if it has more than one "else" transition
                        throw new Exception(Name + " invalid choice state with multiple else transitions");
                    }

                    elseTransition = transition;
                }
            }

            if ((elseTransition != null) && (elseTransition.processEvent(nsfEvent) == NSFEventStatus.NSFEventHandled))
            {
                return NSFEventStatus.NSFEventHandled;
            }

            // If no transition is taken, then the model is ill formed and an exception is thrown.
            throw new Exception(Name + " invalid model with no transition taken from a choice state");
        }
        public TimerAccuracyTest(String name)
        {
            Name = name;
            eventHandler = new NSFEventHandler(name, new NSFEventThread(name));
            testEvent = new NSFEvent(name, eventHandler);

            eventHandler.startEventHandler();
        }
Example #11
0
        /// <summary>
        /// Creates a deep copy, replacing the specified parameters.
        /// </summary>
        /// <param name="source">The new source for the copy.</param>
        /// <param name="destination">The new destination for the copy.</param>
        /// <returns>A copy of the event.</returns>
        /// <remarks>
        /// A common design pattern is to queue data event copies, each with its own unique data payload, to state machines for handling.
        /// </remarks>
        public NSFEvent copy(INSFNamedObject source, INSFEventHandler destination)
        {
            NSFEvent eventCopy = copy();

            eventCopy.Source      = source;
            eventCopy.Destination = destination;
            return(eventCopy);
        }
 /// <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;
 }
Example #13
0
        /// <summary>
        /// Adds a trigger to the list of trigger events.
        /// </summary>
        public void addTrigger(NSFEvent trigger)
        {
            if (trigger == null)
            {
                return;
            }

            triggers.Add(trigger);
        }
 /// <summary>
 /// Removes a reaction to a specified event.
 /// </summary>
 /// <param name="nsfEvent">The event causing the action.</param>
 /// <param name="action">The action taken as a result of the event.</param>
 public void removeEventReaction(NSFEvent nsfEvent, NSFVoidAction <NSFEventContext> action)
 {
     lock (eventHandlerMutex)
     {
         if (eventReactions.ContainsKey(nsfEvent.Id))
         {
             eventReactions[nsfEvent.Id].remove(action);
         }
     }
 }
Example #15
0
        /// <summary>
        /// Adds the specified event to the state machine's event queue.
        /// </summary>
        /// <param name="nsfEvent">The event to queue.</param>
        /// <param name="isPriorityEvent">Flag indicating if the event should be queued to the back of the queue (false) or the front of the queue (true).</param>
        /// <param name="logEventQueued">Flag indicating if an event queued trace should be added to the trace log.</param>
        private void queueEvent(NSFEvent nsfEvent, bool isPriorityEvent, bool logEventQueued)
        {
            if (!isTopStateMachine())
            {
                TopStateMachine.queueEvent(nsfEvent, isPriorityEvent, logEventQueued);
                return;
            }

            lock (stateMachineMutex)
            {
                // Do not allow events to be queued if terminating or terminated,
                // except for run to completion event, which may be queued if terminating to allow proper semantics to continue until terminated.
                if ((TerminationStatus == NSFEventHandlerTerminationStatus.EventHandlerTerminated) ||
                    ((TerminationStatus == NSFEventHandlerTerminationStatus.EventHandlerTerminating) && (nsfEvent != runToCompletionEvent)))
                {
                    return;
                }

                // Handle special case of terminate event by setting status and queuing a single terminate event.
                // Terminate event must be the last event queued to guarantee safe deletion when it is handled.
                if (nsfEvent == terminateEvent)
                {
                    if (TerminationStatus == NSFEventHandlerTerminationStatus.EventHandlerReady)
                    {
                        TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerTerminating;
                    }
                }

                // Event limit detection looks for too many events queued for the state machine.
                // If more than the specified number of events are queued, the state machine will remove
                // its queued events, call the event limit actions, and stop after executing any events queued
                // by the limit actions.
                if ((EventLimitDetectionEnabled) && (QueuedEvents == EventLimit))
                {
                    EventThread.removeEventsFor(this);
                    QueuedEvents = 0;

                    EventLimitActions.execute(new NSFStateMachineContext(this, null, null, null, nsfEvent));

                    // Stop the state machine so that no more event processing occurs until started again
                    stopStateMachine();

                    NSFTraceLog.PrimaryTraceLog.addTrace(NSFTraceTags.ErrorTag, NSFTraceTags.SourceTag, Name, NSFTraceTags.MessageTag, "EventLimit");

                    return;
                }

                nsfEvent.Destination = this;

                EventThread.queueEvent(nsfEvent, isPriorityEvent, logEventQueued);

                ++QueuedEvents;
            }
        }
        /// <summary>
        /// Processes an event.
        /// </summary>
        /// <param name="nsfEvent">The event to process.</param>
        /// <returns>NSFEventStatus.EventHandled if the event is handled, otherwise NSFEventStatus.EventUnhandled.</returns>
        /// <remarks>
        /// This method is for use only by the North State Framework's internal logic.
        /// </remarks>
        protected internal virtual NSFEventStatus processEvent(NSFEvent nsfEvent)
        {
            foreach (NSFTransition transition in outgoingTransitions)
            {
                if (transition.processEvent(nsfEvent) == NSFEventStatus.NSFEventHandled)
                {
                    return(NSFEventStatus.NSFEventHandled);
                }
            }

            return(NSFEventStatus.NSFEventUnhandled);
        }
 public State2Strategy(String name, NSFCompositeState parentState)
     : base(name, parentState)
 {
     // Events
     event3 = new NSFEvent("Event3", this);
     // Regions and states, from outer to inner
     intialState2 = new NSFInitialState("IntialState2", this);
     state4 = new NSFCompositeState("state4", this, null, null);
     state5 = new NSFCompositeState("State5", this, null, null);
     // Transitions, ordered internal, local, external
     intialState2ToState4Transition = new NSFExternalTransition("InitialToState4", intialState2, state4, null, null, null);
     state4ToState5Transition = new NSFExternalTransition("State4ToState5", state4, state5, event3, null, null);
 }
        /// <summary>
        /// Creates an event handler
        /// </summary>
        /// <param name="name">The user defined name for the state machine.</param>
        /// <param name="thread">The thread on which events for the state machine are queued.</param>
        public NSFEventHandler(NSFString name, NSFEventThread thread)
            : base(name)
        {
            EventThread       = thread;
            LoggingEnabled    = true;
            RunStatus         = NSFEventHandlerRunStatus.EventHandlerStopped;
            TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerReady;
            startEvent        = new NSFEvent("Start", this);
            stopEvent         = new NSFEvent("Stop", this);
            terminateEvent    = new NSFEvent("Terminate", this);

            EventThread.addEventHandler(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);
        }
        /// <summary>
        /// Adds a reaction to a specified event.
        /// </summary>
        /// <param name="nsfEvent">The event causing the action.</param>
        /// <param name="action">The action taken as a result of the event.</param>
        public void addEventReaction(NSFEvent nsfEvent, NSFVoidAction <NSFEventContext> action)
        {
            lock (eventHandlerMutex)
            {
                if (!eventReactions.ContainsKey(nsfEvent.Id))
                {
                    eventReactions.Add(nsfEvent.Id, new NSFVoidActions <NSFEventContext>());
                    eventReactions[nsfEvent.Id].setExceptionAction(handleEventReactionException);
                }

                eventReactions[nsfEvent.Id].add(action);
            }
        }
Example #21
0
 /// <summary>
 /// Indicates if the event queue contains an event that matches the specified event.
 /// </summary>
 /// <param name="nsfEvent">The event to match.</param>
 /// <returns>True if the event queue contains a matching event, false otherwise.</returns>
 /// <remarks>
 /// Two events match if they have the same id.  Events may be copied to create new events with the same id.
 /// </remarks>
 public bool hasEvent(NSFEvent nsfEvent)
 {
     lock (threadMutex)
     {
         foreach (NSFEvent queuedEvent in nsfEvents)
         {
             if (queuedEvent.Id == nsfEvent.Id)
             {
                 return(true);
             }
         }
         return(false);
     }
 }
Example #22
0
        /// <summary>
        /// Creates a scheduled action.
        /// </summary>
        /// <param name="name">The name of the scheduled action.</param>
        /// <param name="action">The action to execute.</param>
        /// <param name="eventThread">The thread on which the action will execute.</param>
        /// <remarks>
        /// Use null or String.Empty for the name if no name is desired.
        /// The action will be logged in the trace if the name is anything other than null or String.Empty.
        /// </remarks>
        public NSFScheduledAction(NSFString name, NSFVoidAction <NSFContext> action, NSFEventThread eventThread)
            : base(name)
        {
            Actions += action;
            Actions.setExceptionAction(handleActionException);

            eventHandler        = new NSFEventHandler(Name, eventThread);
            executeActionsEvent = new NSFEvent(Name, this, eventHandler);

            eventHandler.LoggingEnabled = false;
            eventHandler.addEventReaction(executeActionsEvent, executeActions);

            eventHandler.startEventHandler();
        }
        /// <summary>
        /// Handles an event.
        /// </summary>
        /// <param name="nsfEvent">The event to handle.</param>
        /// <returns>Status indicating if the event was handled or not.</returns>
        /// <remarks>
        /// This method is for use only by the North State Framework's internal logic.
        /// It calls the actions associated with the event, if any.
        /// </remarks>
        public NSFEventStatus handleEvent(NSFEvent nsfEvent)
        {
            // Handle status changing events
            if ((nsfEvent == startEvent))
            {
                RunStatus = NSFEventHandlerRunStatus.EventHandlerStarted;
            }
            else if (nsfEvent == stopEvent)
            {
                RunStatus = NSFEventHandlerRunStatus.EventHandlerStopped;
            }
            else if (nsfEvent == terminateEvent)
            {
                TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerTerminated;
                EventThread.removeEventHandler(this);
                return(NSFEventStatus.NSFEventHandled);
            }

            // Don't process events if stopped
            if (RunStatus == NSFEventHandlerRunStatus.EventHandlerStopped)
            {
                return(NSFEventStatus.NSFEventUnhandled);
            }

            // Process the event

            bool actionsToExecute = false;

            lock (eventHandlerMutex)
            {
                if (eventReactions.ContainsKey(nsfEvent.Id))
                {
                    actionsToExecute = true;
                }
            }

            if (actionsToExecute)
            {
                eventReactions[nsfEvent.Id].execute(new NSFEventContext(this, nsfEvent));
                return(NSFEventStatus.NSFEventHandled);
            }
            else
            {
                return(NSFEventStatus.NSFEventUnhandled);
            }
        }
 public MultipleTriggersOnTransitionTest(String name)
     : base(name, new NSFEventThread(name))
 {
     event1 = new NSFEvent("Event1", this);
     event2 = new NSFEvent("Event2", this);
     event3 = new NSFEvent("Evnet3", this);
     event4 = new NSFEvent("Event4", this);
     // Regions and states, from outer to inner
     initialState = new NSFInitialState("InitialTest2", this);
     state1 = new NSFCompositeState("State1", this, null, null);
     state2 = new NSFCompositeState("State2", this, null, null);
     // Transitions, ordered internal, local, external
     initialAToState1Transition = new NSFExternalTransition("InitialAToState1", initialState, state1, null, null, null);
     state1ToState2Transition = new NSFExternalTransition("State1ToState2", state1, state2, event1, null, null);
     state2ToState1Transition = new NSFExternalTransition("State2ToState1", state2, state1, event2, null, null);
     state1ToState2Transition.addTrigger(event3);
     state2ToState1Transition.addTrigger(event4);
 }
Example #25
0
        /// <summary>
        /// Implements the main event processing loop.
        /// </summary>
        protected override void threadLoop()
        {
            while (true)
            {
                // Wait for signal to indicate there's work to do
                signal.wait();

                while (true)
                {
                    NSFEvent nsfEvent = null;

                    lock (threadMutex)
                    {
                        if (nsfEvents.Count != 0)
                        {
                            nsfEvent = nsfEvents.First.Value;
                            nsfEvents.RemoveFirst();
                        }
                    }

                    if (nsfEvent == null)
                    {
                        break;
                    }

                    // Guard a bad event from taking down event thread
                    try
                    {
                        nsfEvent.Destination.handleEvent(nsfEvent);
                    }
                    catch (Exception exception)
                    {
                        handleException(new Exception(Name + " event handling exception", exception));
                    }
                }

                // Thread loop will exit when terminating and all event handlers are terminated
                if ((TerminationStatus == NSFThreadTerminationStatus.ThreadTerminating) && allEventHandlersTerminated())
                {
                    nsfEvents.Clear();
                    return;
                }
            }
        }
        public ExceptionHandlingTest(String name)
            : base(name, new NSFEventThread(name))
        {
            event1 = new NSFEvent("Event1", this);
            event2 = new NSFEvent("Event2", this);

            // Regions and states, from outer to inner
            initialState = new NSFInitialState("InitialTest14", this);
            state1 = new NSFCompositeState("State1", this, null, null);
            state2 = new NSFCompositeState("State2", this, state2EntryActions, null);
            state3 = new NSFCompositeState("State3", this, null, null);
            // Transitions, ordered internal, local, external
            initialToState1Transition = new NSFExternalTransition("InitialToState1", initialState, state1, null, null, null);
            state1ToState2Transition = new NSFExternalTransition("State1ToState2", state1, state2, event1, null, null);
            state2ToState3Transition = new NSFExternalTransition("State2ToState3", state2, state3, event2, null, null);
            state3ToState2Transition = new NSFExternalTransition("State3ToState2", state3, state2, event1, null, null);
            state2ToState1Transition = new NSFExternalTransition("State2ToState1", state2, state1, event1, null, null);
            ExceptionActions += localHandleException;
        }
        public ExtendedRunTest(String name)
            : base(name, new NSFEventThread(name))
        {
            event1 = new NSFEvent("Event1", this);
            event2 = new NSFEvent("Event2", this);

            // Regions and states, from outer to inner
            initialState = new NSFInitialState("InitialTest1", this);
            state1 = new NSFCompositeState("State1", this, null, null);
            state2 = new NSFCompositeState("State2", this, null, null);
            state3 = new NSFCompositeState("State3", this, null, null);

            // Transitions, ordered internal, local, external
            state2ReactionToEvent1 = new NSFInternalTransition("State2ReactionToEvent1", state2, event1, null, state2ReactionToEvent1Actions);
            test1ReactionToEvent2 = new NSFInternalTransition("Test1ReactionToEvent2", this, event2, null, test13ReactionToEvent2Actions);
            initialToState1Transition = new NSFExternalTransition("InitialToState1", initialState, state1, null, null, null);
            state1ToState2Transition = new NSFExternalTransition("State1ToState2", state1, state2, event1, null, null);
            state2ToState3Transition = new NSFExternalTransition("State2ToState3", state2, state3, event2, null, null);
            state3ToState2Transition = new NSFExternalTransition("State3ToState2", state3, state2, event1, null, null);
            state2ToState1Transition = new NSFExternalTransition("State2ToState1", state2, state1, event1, null, null);
        }
Example #28
0
        /// <summary>
        /// Queues the specified event.
        /// </summary>
        /// <param name="nsfEvent">The event to queue.</param>
        /// <param name="isPriorityEvent">Flag indicating if the event should be queued to the back of the queue (false) or the front of the queue (true).</param>
        /// <param name="logEventQueued">Flag indicating if an event queued trace should be added to the trace log.</param>
        public void queueEvent(NSFEvent nsfEvent, bool isPriorityEvent, bool logEventQueued)
        {
            // Do not allow events to be queued if terminated
            if (TerminationStatus == NSFThreadTerminationStatus.ThreadTerminated)
            {
                return;
            }

            lock (threadMutex)
            {
                if (logEventQueued)
                {
                    if (nsfEvent.Source != null)
                    {
                        NSFTraceLog.PrimaryTraceLog.addTrace(NSFTraceTags.EventQueuedTag,
                                                             NSFTraceTags.NameTag, nsfEvent.Name,
                                                             NSFTraceTags.SourceTag, nsfEvent.Source.Name,
                                                             NSFTraceTags.DestinationTag, nsfEvent.Destination.Name);
                    }
                    else
                    {
                        NSFTraceLog.PrimaryTraceLog.addTrace(NSFTraceTags.EventQueuedTag,
                                                             NSFTraceTags.NameTag, nsfEvent.Name,
                                                             NSFTraceTags.SourceTag, NSFTraceTags.UnknownTag,
                                                             NSFTraceTags.DestinationTag, nsfEvent.Destination.Name);
                    }
                }

                if (isPriorityEvent)
                {
                    nsfEvents.AddFirst(nsfEvent);
                }
                else
                {
                    nsfEvents.AddLast(nsfEvent);
                }
            }

            signal.send();
        }
Example #29
0
        /// <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);
        }
 public DeepHistoryTest(String name)
     : base(name, new NSFEventThread(name))
 {
     // Events
     event1 = new NSFEvent("Event1", this);
     event2 = new NSFEvent("Event2", this);
     event3 = new NSFEvent("Event3", this);
     event4 = new NSFEvent("Event4", this);
     event5 = new NSFEvent("Event5", this);
     event6 = new NSFEvent("Event6", this);
     //States
     test2InitialState = new NSFInitialState("InitialTest3", this);
     state1 = new NSFCompositeState("State1", this, null, null);
     state2 = new NSFCompositeState("State2", this, null, null);
     //State 1 Region
     state1InitialState = new NSFInitialState("State1Initial", state1);
     state1History = new NSFDeepHistory("State1History", state1);
     state1_1 = new NSFCompositeState("State1_1", state1, null, null);
     state1_2 = new NSFCompositeState("State1_2", state1, null, null);
     // State1_2 Region
     state1_2InitialState = new NSFInitialState("State1_2Initial", state1_2);
     state1_2_1 = new NSFCompositeState("State1_2_1", state1_2, null, null);
     state1_2_2 = new NSFCompositeState("State1_2_2", state1_2, null, null);
     //Transitions
     // Test1 Region
     test1InitialToState1Transition = new NSFExternalTransition("Test1InitialToState1", test2InitialState, state1, null, null, null);
     state1ToState2Transition = new NSFExternalTransition("State1ToState2", state1, state2, event5, null, null);
     state2ToState1Transition = new NSFExternalTransition("State2ToState1", state2, state1, event6, null, null);
     // State1 Region
     state1InitialToState1HistoryTransition = new NSFExternalTransition("State1InitialToState1History", state1InitialState, state1History, null, null, null);
     state1HistoryToState1_1Transition = new NSFExternalTransition("State1HistoryToState1_1", state1History, state1_1, null, null, null);
     state1_1ToState1_2Transition = new NSFExternalTransition("State1_1ToState1_2", state1_1, state1_2, event1, null, null);
     state1_2ToState1_1Transition = new NSFExternalTransition("State1_2ToState1_1", state1_2, state1_1, event2, null, null);
     // State1_2 Region
     state1_2InitialStateToState1_2_1Transition = new NSFExternalTransition("State1_2InitialStateToState1_2_1", state1_2InitialState, state1_2_1, null, null, null);
     state1_2_1ToState1_2_2Transition = new NSFExternalTransition("State1_2_1ToState1_2_2", state1_2_1, state1_2_2, event3, null, null);
     state1_2_2ToState1_2_1Transition = new NSFExternalTransition("State1_2_2ToState1_2_1", state1_2_2, state1_2_1, event4, null, null);
 }
        public TransitionOrderTest(String name)
            : base(name, new NSFEventThread(name))
        {
            // Events
            event1 = new NSFEvent("Event1", this);
            event2 = new NSFEvent("Event2", this);
            event3 = new NSFEvent("Event3", this);

            // Regions and states, from outer to inner
            initialTest15 = new NSFInitialState("InitialTest16", this);
            state1 = new NSFCompositeState("State1", this, null, null);
            state2 = new NSFCompositeState("State2", this, null, null);
            intialState2 = new NSFInitialState("IntialState2", state2);
            state2_1 = new NSFCompositeState("State2_1", state2, null, state2_1ExitActions);
            state3 = new NSFCompositeState("State3", this, null, null);
            initialState3 = new NSFInitialState("InitialState3", state3);
            state3_1 = new NSFCompositeState("State3_1", state3, null, state3_1ExitActions);
            state4 = new NSFCompositeState("State4", this, null, null);
            errorState = new NSFCompositeState("Error", this, null, null);

            // Transitions, ordered internal, local, external
            initialTest15ToState1Transition = new NSFExternalTransition("InitialTest15ToState1", initialTest15, state1, null, null, null);
            state1ToState2Transition = new NSFExternalTransition("State1ToState2", state1, state2, event2, null, null);
            state1ReactionToEvent1 = new NSFInternalTransition("State1ReactionToEvent1", state1, event1, null, state1ReactionToEvent1Actions);
            state1ToErrorTransition = new NSFExternalTransition("State1ToError", state1, errorState, event1, null, null);

            state2ToState3Transition = new NSFExternalTransition("State2ToState3Transition", state2, state3, event2, null, null);
            state2ToErrorTransition = new NSFExternalTransition("State2ToErrorTransition", state2, errorState, event1, null, null);
            state2ToState2Transition = new NSFLocalTransition("State2ToState2Transition", state2, state2, event1, null, null);
            intialState2ToState2_1Transition = new NSFExternalTransition("intialState2ToState2_1Transition", intialState2, state2_1, null, null, null);

            state3ToState4Transition = new NSFExternalTransition("State3ToState4Transition", state3, state4, event2, null, null);
            state3ToState3Transition = new NSFLocalTransition("State3ToState3Transition", state3, state3, event1, null, null);
            state3ReactionToEvent1 = new NSFInternalTransition("state3ReactionToEvent1", state3, event1, null, state3ReactionToEvent1Actions);
            initialState3ToState3_1Transition = new NSFExternalTransition("InitialState3ToState3_1Transition", initialState3, state3_1, null, null, null);
            state3ToErrorTransition = new NSFExternalTransition("State3ToErrorTransition", state3, errorState, event3, null, null);
        }
Example #33
0
        /// <summary>
        /// Processes an event, evaluating if the event results in the transition firing.
        /// </summary>
        /// <remarks>
        /// This method is for use only by the North State Framework's internal logic.
        /// </remarks>
        protected internal NSFEventStatus processEvent(NSFEvent nsfEvent)
        {
            bool transitionTriggered = false;

            if (triggers.Count == 0)
            {
                transitionTriggered = true;
            }
            else
            {
                foreach (NSFEvent trigger in Triggers)
                {
                    if (trigger.Id == nsfEvent.Id)
                    {
                        transitionTriggered = true;
                        break;
                    }
                }
            }

            if (!transitionTriggered)
            {
                return(NSFEventStatus.NSFEventUnhandled);
            }

            NSFStateMachineContext newContext = new NSFStateMachineContext(Source.TopStateMachine, null, null, this, nsfEvent);

            if (!Guards.execute(newContext))
            {
                return(NSFEventStatus.NSFEventUnhandled);
            }

            fireTransition(newContext);

            return(NSFEventStatus.NSFEventHandled);
        }
        public void queueEvent(NSFEvent nsfEvent)
        {
            lock (eventHandlerMutex)
            {
                // Do not allow events to be queued if terminating or terminated (i.e. not ready)
                if (TerminationStatus != NSFEventHandlerTerminationStatus.EventHandlerReady)
                {
                    return;
                }

                // Handle special case of terminate event by setting status and queuing a single terminate event.
                // Terminate event must be the last event queued to guarantee safe deletion when it is handled.
                if (nsfEvent == terminateEvent)
                {
                    if (TerminationStatus == NSFEventHandlerTerminationStatus.EventHandlerReady)
                    {
                        TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerTerminating;
                    }
                }

                nsfEvent.Destination = this;
                EventThread.queueEvent(nsfEvent, false, LoggingEnabled);
            }
        }
        /// <summary>
        /// Handles an event.
        /// </summary>
        /// <param name="nsfEvent">The event to handle.</param>
        /// <returns>Status indicating if the event was handled or not.</returns>
        /// <remarks>
        /// This method is for use only by the North State Framework's internal logic.
        /// It processes the event using UML defined behavior, including run to completion.
        /// </remarks>
        public NSFEventStatus handleEvent(NSFEvent nsfEvent)
        {
            lock (stateMachineMutex)
            {
                --QueuedEvents;

                // This should only happen if events are queued without using the queueEvent method
                if (QueuedEvents < 0)
                {
                    QueuedEvents = 0;
                }
            }

            // Handle status changing events
            if ((nsfEvent == startEvent))
            {
                RunStatus = NSFEventHandlerRunStatus.EventHandlerStarted;
            }
            else if (nsfEvent == stopEvent)
            {
                RunStatus = NSFEventHandlerRunStatus.EventHandlerStopped;
            }
            else if (nsfEvent == terminateEvent)
            {
                TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerTerminated;
                EventThread.removeEventHandler(this);
                return NSFEventStatus.NSFEventHandled;
            }
            else if (nsfEvent == resetEvent)
            {
                reset();
            }

            // Don't process events if stopped
            if (RunStatus == NSFEventHandlerRunStatus.EventHandlerStopped)
            {
                return NSFEventStatus.NSFEventUnhandled;
            }

            // If not already active, enter state machine at the root
            if (!active)
            {
                enter(new NSFStateMachineContext(this, this, null, null, startEvent), false);
            }

            // Process the event
            NSFEventStatus eventStatus = NSFEventStatus.NSFEventUnhandled;
            try
            {
                eventStatus = processEvent(nsfEvent);

                if (eventStatus == NSFEventStatus.NSFEventHandled)
                {
                    runToCompletion();
                }

                // Consecutive loop detection looks for too many events without the state machine pausing.
                // If more than the specified number of transitions occur without a pause, the state machine will remove
                // its queued events, call the consecutive loop limit actions, and stop after executing any events queued
                // by the actions.
                if (ConsecutiveLoopDetectionEnabled)
                {
                    ++consecutiveLoopCount;

                    if (consecutiveLoopCount == ConsecutiveLoopLimit)
                    {
                        lock (stateMachineMutex)
                        {
                            EventThread.removeEventsFor(this);
                            QueuedEvents = 0;
                        }

                        ConsecutiveLoopLimitActions.execute(new NSFStateMachineContext(this, null, null, null, nsfEvent));

                        // Stop the state machine so that no more event processing occurs until started again
                        stopStateMachine();

                        // Reset consecutive loop count in case state machine is started again
                        consecutiveLoopCount = 0;

                        NSFTraceLog.PrimaryTraceLog.addTrace(NSFTraceTags.ErrorTag, NSFTraceTags.SourceTag, Name, NSFTraceTags.MessageTag, "ConsecutiveLoopLimit");
                    }
                    else if (QueuedEvents == 0)
                    {
                        // If no events are queued for this state machine, then it has paused, indicating it's not in an infinite loop.
                        consecutiveLoopCount = 0;
                    }
                }
            }
            catch (Exception exception)
            {
                handleException(new Exception(nsfEvent.Name + " event handling exception", exception));
            }

            return eventStatus;
        }
        /// <summary>
        /// Adds a trigger to the list of trigger events.
        /// </summary>
        public void addTrigger(NSFEvent trigger)
        {
            if (trigger == null)
            {
                return;
            }

            triggers.Add(trigger);
        }
Example #37
0
 /// <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>
        /// 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;
        }
 /// <summary>
 /// Processes an event.
 /// </summary>
 /// <param name="nsfEvent">The event to process</param>
 /// <returns>NSFEventHandled if the event is acted upon, otherwise NSFEventUnhandled.</returns>
 internal NSFEventStatus processEvent(NSFEvent nsfEvent)
 {
     return activeSubstate.processEvent(nsfEvent);
 }
        /// <summary>
        /// Adds the specified event to the state machine's event queue.
        /// </summary>
        /// <param name="nsfEvent">The event to queue.</param>
        /// <param name="isPriorityEvent">Flag indicating if the event should be queued to the back of the queue (false) or the front of the queue (true).</param>
        /// <param name="logEventQueued">Flag indicating if an event queued trace should be added to the trace log.</param>
        private void queueEvent(NSFEvent nsfEvent, bool isPriorityEvent, bool logEventQueued)
        {
            if (!isTopStateMachine())
            {
                TopStateMachine.queueEvent(nsfEvent, isPriorityEvent, logEventQueued);
                return;
            }

            lock (stateMachineMutex)
            {
                // Do not allow events to be queued if terminating or terminated,
                // except for run to completion event, which may be queued if terminating to allow proper semantics to continue until terminated.
                if ((TerminationStatus == NSFEventHandlerTerminationStatus.EventHandlerTerminated) ||
                    ((TerminationStatus == NSFEventHandlerTerminationStatus.EventHandlerTerminating) && (nsfEvent != runToCompletionEvent)))
                {
                    return;
                }

                // Handle special case of terminate event by setting status and queuing a single terminate event.
                // Terminate event must be the last event queued to guarantee safe deletion when it is handled.
                if (nsfEvent == terminateEvent)
                {
                    if (TerminationStatus == NSFEventHandlerTerminationStatus.EventHandlerReady)
                    {
                        TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerTerminating;
                    }
                }

                // Event limit detection looks for too many events queued for the state machine.
                // If more than the specified number of events are queued, the state machine will remove
                // its queued events, call the event limit actions, and stop after executing any events queued
                // by the limit actions.
                if ((EventLimitDetectionEnabled) && (QueuedEvents == EventLimit))
                {
                    EventThread.removeEventsFor(this);
                    QueuedEvents = 0;

                    EventLimitActions.execute(new NSFStateMachineContext(this, null, null, null, nsfEvent));

                    // Stop the state machine so that no more event processing occurs until started again
                    stopStateMachine();

                    NSFTraceLog.PrimaryTraceLog.addTrace(NSFTraceTags.ErrorTag, NSFTraceTags.SourceTag, Name, NSFTraceTags.MessageTag, "EventLimit");

                    return;
                }

                nsfEvent.Destination = this;

                EventThread.queueEvent(nsfEvent, isPriorityEvent, logEventQueued);

                ++QueuedEvents;
            }
        }
 /// <summary>
 /// Checks if an event is queued for processing.
 /// </summary>
 /// <param name="nsfEvent">The event in queustion.</param>
 /// <returns>True if the event is the in queue, otherwise false.</returns>
 protected bool hasEvent(NSFEvent nsfEvent)
 {
     return EventThread.hasEvent(nsfEvent);
 }
 /// <summary>
 /// Indicates if the event queue contains an event that matches the specified event.
 /// </summary>
 /// <param name="nsfEvent">The event to match.</param>
 /// <returns>True if the event queue contains a matching event, false otherwise.</returns>
 /// <remarks>
 /// Two events match if they have the same id.  Events may be copied to create new events with the same id.
 /// </remarks>
 public bool hasEvent(NSFEvent nsfEvent)
 {
     lock (threadMutex)
     {
         foreach (NSFEvent queuedEvent in nsfEvents)
         {
             if (queuedEvent.Id == nsfEvent.Id)
             {
                 return true;
             }
         }
         return false;
     }
 }
        /// <summary>
        /// Queues the specified event.
        /// </summary>
        /// <param name="nsfEvent">The event to queue.</param>
        /// <param name="isPriorityEvent">Flag indicating if the event should be queued to the back of the queue (false) or the front of the queue (true).</param>
        /// <param name="logEventQueued">Flag indicating if an event queued trace should be added to the trace log.</param>
        public void queueEvent(NSFEvent nsfEvent, bool isPriorityEvent, bool logEventQueued)
        {
            // Do not allow events to be queued if terminated
            if (TerminationStatus == NSFThreadTerminationStatus.ThreadTerminated)
            {
                return;
            }

            lock (threadMutex)
            {
                if (logEventQueued)
                {
                    if (nsfEvent.Source != null)
                    {
                        NSFTraceLog.PrimaryTraceLog.addTrace(NSFTraceTags.EventQueuedTag,
                            NSFTraceTags.NameTag, nsfEvent.Name,
                            NSFTraceTags.SourceTag, nsfEvent.Source.Name,
                            NSFTraceTags.DestinationTag, nsfEvent.Destination.Name);
                    }
                    else
                    {
                        NSFTraceLog.PrimaryTraceLog.addTrace(NSFTraceTags.EventQueuedTag,
                            NSFTraceTags.NameTag, nsfEvent.Name,
                            NSFTraceTags.SourceTag, NSFTraceTags.UnknownTag,
                            NSFTraceTags.DestinationTag, nsfEvent.Destination.Name);
                    }
                }

                if (isPriorityEvent)
                {
                    nsfEvents.AddFirst(nsfEvent);
                }
                else
                {
                    nsfEvents.AddLast(nsfEvent);
                }
            }

            signal.send();
        }
        public ForkJoinToForkJoinTransitionTest(String name)
            : base(name, new NSFEventThread(name))
        {
            // Fork Joins
            bSynch = new NSFForkJoin("BSynch", this);
            abForkJoin = new NSFForkJoin("ABForkJoin", this);
            bcForkJoin = new NSFForkJoin("BCForkJoin", this);
            // ARegion
            // Events
            evA1 = new NSFEvent("EvA1", this);
            // States
            aRegion = new NSFRegion("ARegion", this);
            initialAState = new NSFInitialState("InitialA", aRegion);
            stateA1 = new NSFCompositeState("StateA1", aRegion, null, null);
            stateA2 = new NSFCompositeState("StateA2", aRegion, null, null);
            // Transitions, ordered internal, local, external
            initialAToStateA1Transition = new NSFExternalTransition("InitialAToStateA1", initialAState, stateA1, null, null, null);
            stateA1ToABForkJoinTransition = new NSFExternalTransition("StateA1ToABForkJoin", stateA1, abForkJoin, evA1, null, null);
            abForkJoinToA2Transition = new NSFExternalTransition("ABForkJoinToA2", abForkJoin, stateA2, null, null, null);
            // B Region
            // Events
            evB1 = new NSFEvent("EvB1", this);
            // States
            bRegion = new NSFRegion("BRegion", this);
            initialBState = new NSFInitialState("InitialB", bRegion);
            stateB1 = new NSFCompositeState("StateB1", bRegion, null, null);
            stateB2 = new NSFCompositeState("StateB2", bRegion, null, null);
            // Transitions, ordered internal, local, external
            initialBToStateB1Transition = new NSFExternalTransition("InitialBToStateB1", initialBState, stateB1, null, null, null);
            stateB1ToBSynchTransition = new NSFExternalTransition("StateB1ToBSynch", stateB1, bSynch, evB1, null, null);
            bSynchToStateB2Transition = new NSFExternalTransition("BSynchToStateB2", bSynch, stateB2, null, null, null);
            // C Region
            // Events
            evC1 = new NSFEvent("EvC1", this);
            // States
            cRegion = new NSFRegion("CRegion", this);
            initialCState = new NSFInitialState("InitialC", cRegion);
            stateC1 = new NSFCompositeState("StateC1", cRegion, null, null);
            stateC2 = new NSFCompositeState("StateC2", cRegion, null, null);
            // Transitions, ordered internal, local, external
            initialCToStateC1Transition = new NSFExternalTransition("InitialCToStateC1", initialCState, stateC1, null, null, null);
            stateC1ToBCForkJoinTransition = new NSFExternalTransition("StateC1ToBCForkJoin", stateC1, bcForkJoin, evC1, null, null);
            bcForkJoinToC2Transition = new NSFExternalTransition("BCForkJoinToC2", bcForkJoin, stateC2, null, null, null);

            // Extra Regional Transitions
            bSynchToABForkJoinTransition = new NSFExternalTransition("BSynchToABForkJoin", bSynch, abForkJoin, null, null, null);
            bSynchToBCForkJoinTransition = new NSFExternalTransition("BSynchToBCForkJoin", bSynch, bcForkJoin, null, null, null);
        }
 /// <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 NSF event context.
 /// </summary>
 /// <param name="source">The source of invocation.</param>
 /// <param name="nsfEvent">The event.</param>
 public NSFEventContext(object source, NSFEvent nsfEvent)
     : base(source)
 {
     Event = nsfEvent;
 }
Example #47
0
 /// <summary>
 /// Processes an event.
 /// </summary>
 /// <param name="nsfEvent">The event to process</param>
 /// <returns>NSFEventHandled if the event is acted upon, otherwise NSFEventUnhandled.</returns>
 internal NSFEventStatus processEvent(NSFEvent nsfEvent)
 {
     return(activeSubstate.processEvent(nsfEvent));
 }
 public void queueEvent(NSFEvent nsfEvent)
 {
     queueEvent(nsfEvent, false, LoggingEnabled);
 }
 public void queueEvent(NSFEvent nsfEvent, INSFNamedObject source)
 {
     nsfEvent.Source = source;
     queueEvent(nsfEvent);
 }
Example #50
0
 /// <summary>
 /// Creates an event.
 /// </summary>
 /// <param name="nsfEvent">The event to copy.</param>
 public NSFEvent(NSFEvent nsfEvent)
     : base(nsfEvent.Name)
 {
     construct(nsfEvent.Id, nsfEvent.Source, nsfEvent.Destination);
 }
        /// <summary>
        /// Performs common construction behaviors.
        /// </summary>
        /// <param name="thread">The state machine's thread.</param>
        private void construct(NSFEventThread thread)
        {
            ConsecutiveLoopDetectionEnabled = true;
            ConsecutiveLoopLimit = 1000;
            EventLimitDetectionEnabled = true;
            EventLimit = 100;
            EventThread = thread;
            QueuedEvents = 0;
            LoggingEnabled = true;
            RunStatus = NSFEventHandlerRunStatus.EventHandlerStopped;
            TerminationStatus = NSFEventHandlerTerminationStatus.EventHandlerReady;

            resetEvent = new NSFEvent("Reset", this);
            runToCompletionEvent = new NSFEvent("RunToCompletion", this);
            startEvent = new NSFEvent("Start", this);
            stopEvent = new NSFEvent("Stop", this);
            terminateEvent = new NSFEvent("Terminate", this);

            StateChangeActions.setExceptionAction(handleStateChangeActionException);

            if (isTopStateMachine())
            {
                EventThread.addEventHandler(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>
 /// Checks if an event is queued for handling.
 /// </summary>
 /// <param name="nsfEvent">The event in queustion.</param>
 /// <returns>True if the event is the in queue, otherwise false.</returns>
 public bool hasEvent(NSFEvent nsfEvent)
 {
     return(EventThread.hasEvent(nsfEvent));
 }
 /// <summary>
 /// Creates an event.
 /// </summary>
 /// <param name="nsfEvent">The event to copy.</param>
 public NSFEvent(NSFEvent nsfEvent)
     : base(nsfEvent.Name)
 {
     construct(nsfEvent.Id, nsfEvent.Source, nsfEvent.Destination);
 }
        private void createStateMachine()
        {
            // State Machine Components
            // Define and initialize in the order:
            //   1) Events
            //   2) Regions and states, from outer to inner
            //   3) Transitions, ordered internal, local, external
            //   4) Group states and transitions within a region together.

            // Events
            // Event constructors take the form (name, parent)
            // Data event constructors take the form (name, parent, data payload)
            newCommandEvent = new NSFDataEvent<String>("NewCommand", this, "CommandPayload");
            newResponseEvent = new NSFDataEvent<String>("NewResponse", this, "ResponsePayload");
            responseTimeoutEvent = new NSFEvent("ResponseTimeout", this);
            resetEvent = new NSFEvent("Reset", this);

            // Regions and states, from outer to inner
            // Initial state construtors take the form (name, parent)
            initialCommandProcessorState = new NSFInitialState("InitialCommandProcessor", this);
            // Composite state construtors take the form (name, parent, entry action, exit action)
            waitForCommandState = new NSFCompositeState("WaitForCommand", this, null, null);
            waitForResponseState = new NSFCompositeState("WaitForResponse", this, waitForResponseEntryActions, waitForResponseExitActions);
            errorState = new NSFCompositeState("Error", this, errorEntryActions, null);
            resetState = new NSFCompositeState("Reset", this, resetEntryActions, null);

            // Transitions, ordered internal, local, external
            // Internal transition construtors take the form (name, state, trigger, guard, action)
            reactionToNewCommand = new NSFInternalTransition("ReactionToNewCommand", this, newCommandEvent, null, queueCommand);
            // External transition construtors take the form (name, source, target, trigger, guard, action)
            initialCommandProcessorToWaitForCommandTransition = new NSFExternalTransition("InitialToWaitForCommand", initialCommandProcessorState, waitForCommandState, null, null, null);
            waitForCommandToWaitForResponseTransition = new NSFExternalTransition("WaitForCommandToWaitForResponse", waitForCommandState, waitForResponseState, null, hasCommand, sendCommand);
            waitForResponseToWaitForCommandTransition = new NSFExternalTransition("WaitForResponseToWaitForCommand", waitForResponseState, waitForCommandState, newResponseEvent, isResponse, handleResponse);
            waitForResponseToErrorTransition = new NSFExternalTransition("WaitForResponseToError", waitForResponseState, errorState, responseTimeoutEvent, null, null);
            errorToResetTransition = new NSFExternalTransition("ErrorToReset", errorState, resetState, resetEvent, null, null);
            resetToWaitForCommandTransition = new NSFExternalTransition("ResetToWaitForCommand", resetState, waitForCommandState, null, isReady, null);
        }
 /// <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="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);
        }
 public void queueEvent(NSFEvent nsfEvent, INSFNamedObject source)
 {
     nsfEvent.Source = source;
     queueEvent(nsfEvent);
 }
Example #59
0
 /// <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>
        /// Processes an event, evaluating if the event results in the transition firing.
        /// </summary>
        /// <remarks>
        /// This method is for use only by the North State Framework's internal logic.
        /// </remarks>
        protected internal NSFEventStatus processEvent(NSFEvent nsfEvent)
        {
            bool transitionTriggered = false;

            if (triggers.Count == 0)
            {
                transitionTriggered = true;
            }
            else
            {
                foreach (NSFEvent trigger in Triggers)
                {
                    if (trigger.Id == nsfEvent.Id)
                    {
                        transitionTriggered = true;
                        break;
                    }
                }
            }

            if (!transitionTriggered)
            {
                return NSFEventStatus.NSFEventUnhandled;
            }

            NSFStateMachineContext newContext = new NSFStateMachineContext(Source.TopStateMachine, null, null, this, nsfEvent);

            if (!Guards.execute(newContext))
            {
                return NSFEventStatus.NSFEventUnhandled;
            }

            fireTransition(newContext);

            return NSFEventStatus.NSFEventHandled;
        }