Event collector example

It is possible to fire events from the behavior of a state or a transition (this feature was introduced in version 1.1.0).

To demonstrate this feature, we implemented a state machine according to the following state machine diagram:


This scenario includes:

  • The simple state 'S2' has a do behavior in which an E3 event is "pushed" in the event queue.

  • The transition from 'S4' to 'S3' is a completion transition that has a behavior in which an event E4 is "pushed" in the event queue.

  • The event E4 contains a message (string) as parameter.

  • Only the event E1 is fired outside of the state machine.

  • The transition triggered by the E4 from the simple state 'S3' to the final state will have a behavior that will display the message carried by the E4 event.

After the state machine is started, 'S1' will become the active state. As E1 is fired, the transition from 'S1' to 'S2' is executed and the do behavior of 'S2' is executed as well. This behavior gets a reference to the interface event_collector as parameter. Using this interface the event E3 is pushed into the event queue.

Then the events in the queue are executed next, thus E3 will be processed. Then the completion transition from state 'S4' is taken. This transition has a behavior that enqueues the event E4 (via push), therefore when 'S3' becomes active (and because no completion transition is found), the event E4 will be processed and the transition to final state is taken.

Methods as behaviors

All three methods presented in this examples are encapsulated inside a simple class named 'action'.

The method used as behavior for simple state 'S2' looks like this:

void action::fire_event_E3( sxy::event_collector& _event_collector )
_event_collector.push( examples::E3::create() );

Event E3 will be pushed into the event queue via the event_collector interface.

The method for the completion transition from 'S4' to 'S3' looks like this:

void action::fire_event_E4( sxy::event_collector& _event_collector )
_event_collector.push( examples::E4::create( "The transition from simple state 'S3' to the final state has been executed!" ) );

A new event E4 is created and pushed into the event_queue by the event collector . This event carries a message.

Finally the behavior of the transition from simple state 'S3' to the final state triggered by the event E4 looks like this:

void action::print_message_from_event( const E4& _event )
std::cout << _event.get_message() << std::endl;

The message carried by the event E4 will be shown in the console.

Using the methods

The state machine is a member of the 'machine' class. The 'machine' class creates and runs the state machine. The 'action' class, which contains the methods that are used as behaviors, is also a member of the class 'machine'.

state_machine_uptr machine::setup_state_machine( const std::string& _name )
action* action_ptr = &action_;
sxy::simple_state& s2 = main_region.add_simple_state( "S2",
Y_BEHAVIOR_METHOD2( action_ptr, &examples::action::fire_event_E3 ), Y_EMPTY_BEHAVIOR, Y_EMPTY_BEHAVIOR );
state_machine->add_transition( sxy::Y_COMPLETION_EVENT_ID, s4, s3,
Y_BEHAVIOR_METHOD2( action_ptr, &examples::action::fire_event_E4 ) );
state_machine->add_transition( examples::E4::get_event_id(), s3, final,
Y_BEHAVIOR_METHOD2( action_ptr, &examples::action::print_message_from_event ) );

In the code above the macro Y_BEHAVIOR_METHOD2 is used to adapt the methods of the class 'action' as behaviors for the state machine elements (state and transitions). The macro takes 2 or more parameters. First a pointer to the object on which the methods are supposed to be called is passed followed by one or more (up to 10) method pointers which are supposed to be used as behaviors. The methods passed to the macro have to take the different kinds of events that can be encountered when executing the corresponding transition or state behaviors.

The usage of the Y_BEHAVIOR_METHOD2 macro is the same for the transition and states behaviors.

Source code

The source code can be found on GitHub.