Tutorial 8 — Events and State Reactors
Events drive every state transition in SMACC2. In the basic tutorials you used framework-provided events like EvTimer and EvCbSuccess. In this tutorial you will learn to define custom events, understand typed events, and use state reactors to combine multiple events into complex transition logic.
Custom Events
Define a custom event as a struct inheriting from sc::event<>:
// In sm_three_some.hpp
struct EvToDeep : sc::event<EvToDeep> {};
struct EvFail : sc::event<EvFail> {};
Custom events are simple — they carry no template parameters and no data. They are useful for cross-state signaling, error handling, and mode switching.
Use them in a transition table:
typedef mpl::list<
Transition<EvFail, MsRecover, ABORT>
>reactions;
Any code with access to the state machine can post a custom event:
this->postEvent<EvFail>();
Typed Events
Most SMACC2 events are typed — they carry template parameters identifying their source behavior and orthogonal:
EvTimer<CbTimerCountdownOnce, OrTimer>
EvCbSuccess<CbArmPX4, OrPx4>
EvKeyPressN<CbDefaultKeyboardBehavior, OrKeyboard>
EvTopicMessage<ClSubscriber, OrSubscriber>
The type parameters serve two purposes:
Disambiguation — when multiple orthogonals could fire the same event type, the orthogonal parameter tells the transition table exactly which one to match.
Traceability — the RTA viewer and logs show exactly which behavior on which orthogonal produced the event.
You define your own typed events the same way:
template <typename TSource, typename TOrthogonal>
struct EvHttp : sc::event<EvHttp<TSource, TOrthogonal>> {};
The event is then posted using onStateOrthogonalAllocation<>() which captures the type parameters at compile time (see Tutorial 3 — Orthogonals and Concurrent Behaviors for the CbHttpRequest example).
State Reactors
A state reactor watches for multiple events and fires a single output event when a condition is met. This is useful when a state needs to wait for several things to happen before transitioning.
SrAllEventsGo
SrAllEventsGo waits for all specified events to arrive, then fires its output event. From sm_three_some’s st_state_2.hpp:
struct StState2 : smacc2::SmaccState<StState2, MsRun>
{
using SmaccState::SmaccState;
typedef mpl::list<
Transition<EvTimer<CbTimerCountdownOnce, OrTimer>, StState3, TIMEOUT>,
Transition<EvAllGo<SrAllEventsGo>, StState3>,
Transition<EvKeyPressP<CbDefaultKeyboardBehavior, OrKeyboard>,
StState1, PREVIOUS>,
Transition<EvKeyPressN<CbDefaultKeyboardBehavior, OrKeyboard>,
StState3, NEXT>
>reactions;
static void staticConfigure()
{
configure_orthogonal<OrTimer, CbTimerCountdownOnce>(10);
configure_orthogonal<OrSubscriber, CbWatchdogSubscriberBehavior>();
configure_orthogonal<OrKeyboard, CbDefaultKeyboardBehavior>();
// State reactor: wait for keys A, B, and C to all be pressed
static_createStateReactor<
SrAllEventsGo,
EvAllGo<SrAllEventsGo>,
mpl::list<
EvKeyPressA<CbDefaultKeyboardBehavior, OrKeyboard>,
EvKeyPressB<CbDefaultKeyboardBehavior, OrKeyboard>,
EvKeyPressC<CbDefaultKeyboardBehavior, OrKeyboard>
>
>();
}
};
How it works:
SrAllEventsGois created with a list of input events (A, B, C key presses).As each input event arrives, the reactor marks it as received.
When all input events have been received, it posts the output event
EvAllGo<SrAllEventsGo>.The transition table matches
EvAllGoand transitions toStState3.
The reactor coexists with other transitions — the timer timeout at 10 seconds is a fallback that fires regardless of the reactor.
Other State Reactors
Reactor |
Behavior |
|---|---|
|
Fires output when all input events received |
|
Fires one of two output events based on a boolean condition |
|
Fires output after receiving N occurrences of an event |
Creating a State Reactor
Use static_createStateReactor<>() in staticConfigure():
static_createStateReactor<
ReactorType, // e.g. SrAllEventsGo
OutputEvent, // e.g. EvAllGo<SrAllEventsGo>
mpl::list<InputEvents...> // events to watch
>();
The reactor is state-scoped — it is created when the state is entered and destroyed when the state exits.
Summary
You learned:
Custom events:
struct EvFail : sc::event<EvFail> {}Typed events with
<TSource, TOrthogonal>template parameters for disambiguationState reactors that combine multiple events into complex transition logic
SrAllEventsGo,SrConditional, andSrEventCountdownstatic_createStateReactor<>()for declaring reactors instaticConfigure()
Next Steps
In Tutorial 9 — Hierarchical States you will learn how to group states into hierarchical states with mode states, super states, and loop control.