Click here to Skip to main content
Click here to Skip to main content

Construction of UML State Machines Using C/C++ Macros

, 6 Jun 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
In this article, a set of C macros is presented to help construct UML state machines.

Introduction

In general, a UML hierarchical state machine (HSM)[2] is any device that stores the status of something at a given time, and can operate on input to change the status and/or cause an action or output to take place for any given change. A hierarchical state machine should include the following elements:

  • A set of hierarchical states
  • An initial state
  • A set of input events
  • A set of output events
  • A set of actions that map states and input events to an output (called state event handlers)
  • A set of actions that map states and inputs to other states (called state transitions)

Considerable work has been done on implementing a hierarchical state machine in standard programming languages. The most common technique to implement a state machine is the doubly nested switch statements, with a "scalar variable" used as the discriminator in the first level of the switch, and an event-type in the second level [2][3]. This works well for classical "flat" state machines, and is widely employed by automatic code synthesizing tools. Manual coding of entry/exit actions and nested states is, however, cumbersome, mainly because code pertaining to one state becomes distributed and repeated in many places, making it difficult to modify and maintain when the topology of the state machine changes.

Another technique is the object-oriented "State" design technique, based on delegation and polymorphism [2][3]. States are represented as subclasses implementing a common interface (each method in this interface corresponds to an event). A context class delegates all the events for processing to the current state object. State transitions are accomplished by changing the current state object (typically re-assigning a pointer). This pattern is elegant, but is not hierarchical. Accessing context attributes from state methods is indirect (cannot use an implicit pointer) and breaks encapsulation. The addition of new states requires sub-classing, and the addition of new events requires adding new methods to the common interface. Also, this technique may suffer from efficiency problems.

Construction of UML State Machines Using C Macros

Our implementation of the HSM pattern is, to some degree, through action-state tables containing typically sparse arrays of actions and transitions for each state. Actions (including entry/exit, state reactions, and actions associated with transitions) are most commonly represented as pointers to functions. Representing state hierarchy in a flat action-state table is sometimes cumbersome, and does not always impart the complete design. We chose an easy-to-use problem where we define a series of macros as state machine mapping data. This makes it possible for users to employ the state machine's builder task without any pre-knowledge on the internal implementation. On the other hand, the mapping data can be parsed by an add-in in IDE to reconstruct state machines when source code files are modified.

In this article, a set of C macros named the StateWizard API is present to construct state machines. Meanwhile, for the sake of performance, the StateWizard provides two versions of API sets, C and C++ versions. Using the C++ version, users can utilize C++ features such as inheritance and virtual functions.

UML defines three types of states:

  • Simple States (Leaf States): Simplest of all states, they have no sub-states.
  • Composite States: Have one or more regions for substates. A region is simply a container for substates.

    A composite state is a state that consists of sub-states. A composite state can be decomposed using AND-relationships into two or more concurrent regions which are containers for sub-states, or using OR-relationships into mutually exclusive disjoint sub-states.

    A composite state which can be decomposed using AND-relationships into two or more concurrent regions is called an Orthogonal state.

  • Submachine States: Semantically equaling to composite states, submachine states have substates that are contained within a substate machine. Unlike composite states, submachine states are intended to group states, so you can reuse them.

A system's overall behavior can be broken down into individual states. For example, a tape recorder can be on or off. These are two distinct states.

A state can be as brief as a fraction of a second, or extend to several seconds, minutes, or hours. Each state, no matter how brief, is a distinct unit within the system's life cycle. A State Machine allows you to depict all the states of a system as they occur in real-life.

What is more, each state is a collection of several actions which the State Machine performs when the state is active. These actions take place upon entry into the state, or upon exit from the state.

A UML state chart allows developers to model complex behavior via composite states with more than one hierarchy level:

  • Similar sub-states are grouped into a composite state (a nesting hierarchy is a tree); composite states can have transitions, entry/exit actions, ... (transitions can connect states from different nesting levels).
  • Sub-states "inherit" from the composite state.
  • An active state denotes a path from a top-level state to a leaf node in the state hierarchy.
  • There must be an initial sub-state in every composite state. On entering a compose state or sub-state, both of them are activated. The order of the entry functions is from top to bottom.
  • On exiting a composite state, exit the active sub-state as well. The order of the exit functions is from bottom to top.

The state machine state hierarchy is based on a parent-child relationship, which is depicted by the arrangement of tree branches. For example, the node Application in the state tree below is a root state which has two children: PowerDown and PowerUp. Meanwhile, the node PowerUp is also a parent of three children, and these children are referred as sibling states among them.

This hierarchical organization means that when a transition from state PowerDown to PowerUp is triggered, the state machine de-activates the state PowerDown and its children (if any) and activates PowerUp and one or more of its children (if any).

Figure: State Hierarchy in Tree Form:
Application 
__|-- PowerDown (Default) 
__|-- PowerUp 
______|-- Playing (Default) 
______|-- Pause 
______|-- Record

Root state

is the uppermost state, bearing the application name. As you add states, the state tree grows downwards from the root state.

For example, the Player composite state is the root state of the Player state machine. It is defined as below. The PlayerEntry and PlayerExit are the function pointers to the actions on the root state entry and exit, respectively.

SME_BEGIN_ROOT_COMP_STATE_DEF(Player, PlayerEntry, PlayerExit) 

Parent state

is a state that branches into one or more child states. A parent can have several children, but a child has only one parent.

For example, the PowerUp composite state's parent state is the state Player. Define the PowerUp state as below:

SME_BEGIN_COMP_STATE_DEF(PowerUp, Player, PowerUpEntry, PowerUpExit) 

Initial child state

identifies the initial state for state machines that have substates. This child must occur if and only if the machine has one or more states or parallel children.

For example, an initial child state Playing of the PowerUp composite state is defined as below. OnPowerUpInitChild is a function pointer to the initial child state entry action.

SME_BEGIN_COMP_STATE_DEF(PowerUp, Player, PowerUpEntry, PowerUpExit) 
SME_ON_INIT_STATE(OnPowerUpInitChild, Playing) 
SME_END_STATE_DEF

Sibling states

are the child states with a common parent.

Using the StateWizard application framework API set, the sibling states under a parent state are defined below a composite state declaration. For example, the children sibling states Playing, Pause, and Record of the PowerUp composite state are defined as below:

SME_BEGIN_COMP_STATE_DEF(PowerUp, Player, PowerUpEntry, PowerUpExit) 
SME_ON_INIT_STATE(OnPowerUpInitChild, Playing) 
SME_END_STATE_DEF

SME_BEGIN_LEAF_STATE_DEF_P(Playing, PlayingEntry, PlayingExit) 
SME_ON_EVENT(EXT_EVENT_ID_PAUSE_RESUME,OnPlayingEXT_EVENT_ID_PAUSE_RESUME,Pause) 
SME_END_STATE_DEF 

SME_BEGIN_LEAF_STATE_DEF_P(Pause, PauseEntry, PauseExit) 
SME_ON_EVENT(EXT_EVENT_ID_PAUSE_RESUME,OnPauseEXT_EVENT_ID_PAUSE_RESUME,Playing) 
SME_END_STATE_DEF 

SME_BEGIN_LEAF_STATE_DEF_P(Record, RecordEntry, RecordExit) 
SME_ON_EVENT(EXT_EVENT_ID_STOP_RECORD,OnRecordEXT_EVENT_ID_STOP_RECORD,PowerDown) 
SME_END_STATE_DEF

The API set for state construction:

SME_BEGIN_ROOT_COMP_STATE_DEF(_root_state, _entry, _exit) 

The SME_BEGIN_ROOT_COMP_STATE_DEF macro declares the header of a root state definition. This macro maps to a structure variable in the SME_STATE_T type.

Parameters:

  • _state: The root state name. It maps to a text string.
  • _entry: The function name of the state entry action. It maps to a C/C++ function pointer.
  • _exit: The state exit action function. It maps to a C/C++ function pointer.
SME_BEGIN_LEAF_STATE_DEF(_state, _parent, _entry, _exit)

The SME_BEGIN_LEAF_STATE_DEF macro declares the header of a simple / leaf state definition.

Parameters:

  • _state: The leaf state name.
  • _parent: The parent state. It maps to a C/C++ pointer to the parent state.
  • _entry: The function name of the state entry action. It maps to a C/C++ function pointer.
  • _exit: The state exit action function. It maps to a C/C++ function pointer.
SME_BEGIN_COMP_STATE_DEF(_state, _parent, _entry, _exit)

The SME_BEGIN_COMP_STAE_DEF macro declares the header of the internal behavior definition for a composite state.

A composite state has an internal behavior, which is the entry/exit functions, initial state, internal event/transitions, child states, and the transitions among these child states. These are defined in the COMP (component) definition and the appropriate definitions of all the sub-states.

It also has an external behavior, which is its interaction with its parent and siblings. This is defined in the SUB definition.

If a state has no child states, a leaf state, or a pseudo state, it only has an external behavior, thus the COMP def is not necessary, and the complete behavior can be defined in LEAF/COND/JOIN definitions.

A hierarchical state machine is divided into several levels through COMP_STATE and SUB_STATE definitions. The reason is to provide some sort of modularity/information hiding, by hiding the real destination from deeper states.

Parameters:

  • _state: The composite state name.
  • _parent: The parent state. It maps to a C/C++ pointer to the parent state.
  • _entry: The function name of the state entry action. It maps to a C/C++ function pointer.
  • _exit: The state exit action function. It maps to a C/C++ function pointer.
SME_BEGIN_SUB_STATE_DEF(_state, _parent)

The SME_BEGIN_SUB_STATE_DEF macro declares the header of the external behavior definition for a composite state.

The SUB definition holds a pointer to the sub-machine's internal behaviors. The COMP def appears in the file which defines the internals of the state, and the SUB may appear in a different file, the one defining the behavior of the state's parent, thus defining the external behavior of the state. For example, a state transition from this composite state to its sibling state may be defined in the SUB definition body.

Parameters:

  • _state: The composite state name.
  • _parent: The parent state. It maps to a C/C++ pointer to the parent state.
SME_END_STATE_DEF 

The SME_END_STATE_DEF macro declares the end of a state definition.

Parameters: None.

SME_ON_INIT_STATE( _handler, _new_state) 

The SME_ON_INIT_STATE macro declares the initial child state of a composite state.

Parameters:

  • _handler: The function name of the initial child state entry action. It maps to a C/C++ function pointer.
  • _new_state: The initial child state. It maps to a C/C++ pointer to the initial child state.
SME_BEGIN_LEAF_STATE_DEF_P(_state, _entry, _exit) 
SME_BEGIN_SUB_STATE_DEF_P(_state) 
SME_BEGIN_COND_STATE_DEF_P(_state, _cond) 
SME_BEGIN_JOIN_STATE_DEF_P

The macros ending with _P uses the preprocessor SME_CURR_DEFAULT_PARENT as their parent state. They are defined as below:

#define SME_BEGIN_LEAF_STATE_DEF_P(_state, _entry, _exit) \ 
SME_BEGIN_LEAF_STATE_DEF(_state, SME_CURR_DEFAULT_PARENT, _entry, _exit) 

#define SME_BEGIN_SUB_STATE_DEF_P(_state) \ 
SME_BEGIN_SUB_STATE_DEF(_state, SME_CURR_DEFAULT_PARENT) 

#define SME_BEGIN_COND_STATE_DEF_P(_state, _cond) \ 
SME_BEGIN_COND_STATE_DEF(_state, SME_CURR_DEFAULT_PARENT, _cond) 

#define SME_BEGIN_JOIN_STATE_DEF_P(_state) \ 
SME_BEGIN_JOIN_STATE_DEF(_state, SME_CURR_DEFAULT_PARENT)

Events

An event is an object that takes place at certain point of time. An event may contain some data.

A transition describes the change from one state to another state. A transition is comprised of:

  • A destination: the state which the state machine activates when the transition takes place.
  • A trigger: a certain condition within the application that initiates the transition.

In addition, a transition can also contain one or more actions to be executed when the transition is triggered.

The order of operations during a transition will be:

  1. source state exit function,
  2. event handler function, if available,
  3. and then the destination state entry function.

Transitions

A transition shows the relationship, or path, between two states or pesudo-states. It represents the actual change in the configuration of a state machine as it heads from one state to the next. Each transition can have a guard condition that indicates if the transition can even be considered (enabled), a trigger that causes the transition to execute if it is enabled, and the effect the transition may have when it occurs. Transitions are shown as a line between two states, with an arrowhead pointing to the destination state. You specify the details of the transition using the following syntax:

trigger [guard] / actions

where:

  • trigger:

    Indicates what condition may cause this transition to occur. The trigger is typically the name of an event, though it may be more complex.

  • guard:

    Is a constraint that is evaluated when an event is fired by the state machine to determine if the transition should be enabled. Guards should not have any side effects, and must evaluate to a boolean. Guards will always be evaluated before a transition is fired.

  • actions:

    In addition, a transition can also contain one or more actions to be executed when the transition is triggered.

For example, in the Pause state, on an event EXT_EVENT_ID_PAUSE_RESUME, the OnPauseEXT_EVENT_ID_PAUSE_RESUME() action will be called, and transits to the Playing state.

SME_BEGIN_LEAF_STATE_DEF_P(Pause, PauseEntry, PauseExit) 
SME_ON_EVENT(EXT_EVENT_ID_PAUSE_RESUME,OnPauseEXT_EVENT_ID_PAUSE_RESUME,Playing) 
SME_END_STATE_DEF

For example, in the Playing state, on a timeout event SME_EVENT_TIMER, check the guard which is defined in the GuardTimer_func() function. If the evaluation of the guard is true, fire the internal transition, and call the action OnTimerProc.

SME_BEGIN_LEAF_STATE_DEF_P(Playing, PlayingEntry, PlayingExit) 
SME_ON_INTERNAL_TRAN_WITH_GUARD(SME_EVENT_TIMER,GuardTimer_func,OnTimerProc) 
SME_END_STATE_DEF

The order of operations during a transition is:

  1. source state exit function,
  2. event handler function if available,
  3. and then the destination state entry function.

If a transition is triggered between different hierarchy levels, or the source state and the destination state are not sibling states, the operation sequence during the transition will be more complex.

Transition types

UML defines several specific types of transitions. These are described in the following list. There are no special symbols associated with transition types. They are defined only for clarity and common vocabulary.

  • Compound transition

    A representation of the change from one complete state machine configuration to another. Compound transitions are a set of transitions, choices, forks, and joins, leading to a set of target states.

  • High-level transition

    A transition from a composite state. If the destination of the transition is outside the composite state, all the substates are exited, and their exit activities are run followed by the exit activity of the composite. If the transition ends with a target inside the composite state, the exit activity of the composite state isn't run.

    The example is a state machine belonging to a player machine. The default transition from PowerDown to PowerUp will change to the initial sub-state: Playing of the composite state: PowerUp.

    Player Application 
    __|--> PowerDown (Init) 
    __|--> PowerUp 
    ______|--> Playing (Init) 
    ______|--> Pause 
    ______|--> Record
    Figure: High-level Transition

    Using the framework API set, the high-level transition from the PowerDown state to the PowerUp state is defined as below:

    SME_BEGIN_LEAF_STATE_DEF_P(PowerDown, PowerDownEntry, PowerDownExit) 
    SME_ON_EVENT(EXT_EVENT_ID_POWER, OnPowerDownEXT_EVENT_ID_POWER, PowerUp) 
    SME_END_STATE_DEF
  • Internal transition

    An internal transition is different from a self transition. Internal transitions allow execution of actions that are triggered by events without leaving the state. The state entry and exit actions are not dispatched.

  • History transition

    A History state is used to remember the previous state of a state machine when it was interrupted.

    Player Application 
    __|--> Power Down (Init) 
    __|--> Power Up (H) 
    ______|--> Stop (Init) 
    ______|--> Play 
    ______|--> Record
    Figure: History Transition

    Take the above player state machine as an example. In this state machine, when a Player machine is running at Record state, and if there is a power cut, the Player machine will stop running and will go to the Power Down state. Then, when the power is restored, a history transition from Power Down to Power Up is triggered. The running state is entered at the history state Record meaning that it should resume where it last left-off.

    The default transition from Power Down to Power Up will change to the default sub-state: Stop of the composite state: PowerUp.

Transitions and composite states

A transition from an external state to the border of a composite state is called default entry. The entry activity of the composite state is executed, and then the default transition to a substate occurs.

A transition from an external state to a specific substate of a composite state is called explicit entry. The entry activity for the composite state is executed before the substate becomes active.

Whenever a state machine transitions to an orthogonal composite state (a composite state with two or more regions), each region is entered either explicitly or by default. If the composite state is entered through an explicit entry, any other region is entered using its default transition.

SME_ON_EVENT(_EventID, _Handler, _NewState)

The SME_ON_EVENT macro declares a state transition on an event that has occurred.

Parameters:

  • _EventID: The event identifier.
  • _Handler: The function name of the event handler action. It maps to a C/C++ function pointer.
  • _NewState: The destination state on the state transition. It maps to a C/C++ pointer to the destination state.
SME_ON_EVENT_WITH_GUARD(_EventID, _Guard, _Handler, _NewState) 

The SME_ON_EVENT_WITH_GUARD macro declares a state transition with a guard on an event that has occurred.

Parameters:

  • _EventID: The event identifier.
  • _Guard: The guard function that is evaluated when an event is fired by the state machine to determine if the transition should be enabled.
  • _Handler: The function name of the event handler action. It maps to a C/C++ function pointer.
  • _NewState: The destination state on the state transition. It maps to a C/C++ pointer to the destination state.
SME_ON_INTERNAL_TRAN(_EventID, _Handler) 

The SME_ON_INTERNAL_TRAN macro declares an internal state transition on an event that has occurred.

Parameters:

  • _EventID: The event identifier.
  • _NewState: The destination state on the state transition. It maps to a C/C++ pointer to the destination state.
SME_ON_INTERNAL_TRAN_WITH_GUARD(_EventID, _Guard, _Handler) 

The SME_ON_INTERNAL_TRAN_WITH_GUARD macro declares an internal state transition with a guard on an event has occurred.

Parameters:

  • _EventID: The event identifier.
  • _NewState: The destination state on the state transition. It maps to a C/C++ pointer to the destination state.

Sample:

Using the StateWizard application framework API set which is defined in sme.h, the Player state machine is defined as below:

/* The definition of the Player composite root state. */ 
#define SME_CURR_DEFAULT_PARENT Player 
SME_BEGIN_ROOT_COMP_STATE_DEF(Player, PlayerEntry, PlayerExit) 
SME_ON_INIT_STATE(SME_NULL_ACTION, PowerDown) 
SME_END_STATE_DEF 
SME_BEGIN_LEAF_STATE_DEF_P(PowerDown, PowerDownEntry, PowerDownExit) 
SME_ON_EVENT(EXT_EVENT_ID_POWER, OnPowerDownEXT_EVENT_ID_POWER, PowerUp) 
SME_END_STATE_DEF 
SME_BEGIN_SUB_STATE_DEF_P(PowerUp) 
SME_ON_EVENT(EXT_EVENT_ID_POWER,OnPowerUpEXT_EVENT_ID_POWER,PowerDown) 
SME_END_STATE_DEF

/* The definition of the PowerUp composite root state. */ 
#define SME_CURR_DEFAULT_PARENT PowerUp 
SME_BEGIN_COMP_STATE_DEF(PowerUp, Player, PowerUpEntry, PowerUpExit) 
SME_ON_INIT_STATE(OnPowerUpInitChild, Playing) 
SME_END_STATE_DEF 
SME_BEGIN_LEAF_STATE_DEF_P(Playing, PlayingEntry, PlayingExit) 
SME_ON_EVENT(EXT_EVENT_ID_PAUSE_RESUME,OnPlayingEXT_EVENT_ID_PAUSE_RESUME,Pause) 
SME_END_STATE_DEF 
SME_BEGIN_LEAF_STATE_DEF_P(Pause, PauseEntry, PauseExit) 
SME_ON_EVENT(EXT_EVENT_ID_PAUSE_RESUME,OnPauseEXT_EVENT_ID_PAUSE_RESUME,Playing) 
SME_END_STATE_DEF 
SME_BEGIN_LEAF_STATE_DEF_P(Record, RecordEntry, RecordExit) 
SME_ON_EVENT(EXT_EVENT_ID_STOP_RECORD,OnRecordEXT_EVENT_ID_STOP_RECORD,PowerDown) 
SME_END_STATE_DEF

PseudoState

A PseudoState is an abstraction of different types of nodes in the state machine graph which represent transient points in transition paths from one state to another (e.g., branch and fork points). Pseudo states are used to construct complex transitions from simple transitions. For example, by combining a transition entering a fork pseudo state with a set of transitions exiting the fork pseudo state, we get a complex transition that leads to a set of target states.

Conditional (Fork) PseudoStates

are a notational shorthand for multiple exiting transitions all triggered by the same event but each having different guards.

Join PseudoState

a state with several incoming transitions and a single outgoing one.

Using the StateWizard application framework API set, a conditional pseudo state Cond1 and a join pseudo state Join1 are defined as below. The Cond1 pseudo state has three forks: COND1, COND2, and COND_ELSE. The exit destination state is dependent on the return value of the function Cond1_func. The action on entry to the Join1 pseudo state is the JoinAct function.

/* The definition of the Player composite root state. */ 
SME_BEGIN_ROOT_COMP_STATE_DEF(Player, PlayerEntry, PlayerExit) 
SME_ON_INIT_STATE(SME_NULL_ACTION, PowerDown) 
SME_END_STATE_DEF 
.... 
SME_BEGIN_COND_STATE_DEF_P(Cond1, Cond1_func) 
SME_ON_EVENT(COND_EV_COND1, CondAct1, Playing) 
SME_ON_EVENT(COND_EV_COND2, CondAct2, Pause) 
SME_ON_EVENT(SME_EVENT_COND_ELSE, CondActElse, PowerUp) 
SME_END_STATE_DEF 
SME_BEGIN_JOIN_STATE_DEF_P(Join1) 
SME_ON_JOIN_TRAN(JoinAct, Cond1) 
SME_END_STATE_DEF 
SME_BEGIN_JOIN_STATE_DEF(_state, _parent)

The SME_BEGIN_JOIN_STATE_DEF macro declares the header of a join pseudo state definition.

Parameters:

  • _state: The state name.
  • _parent: The parent state. It maps to a C/C++ pointer to the parent state.
SME_BEGIN_COND_STATE_DEF(_state, _parent, _cond)

The SME_BEGIN_COND_STATE_DEF macro declares the header of a conditional pseudo state definition.

Parameters:

  • _state: The state name.
  • _parent: The parent state. It maps to a C/C++ pointer to the parent state.
  • _cond: The condition evaluation function. It maps to a C/C++ function pointer.
SME_ON_JOIN_TRAN( _handler, _state)

The SME_ON_JOIN_TRAN macro declares the join action and the outgoing state.

Parameters:

  • _state: The outgoing state.
  • _handler: The join action function. It maps to a C/C++ function pointer.

Appendix

Note that the complete macro definitions are located in the sme.h header file.

struct SME_STATE_T_TAG
{
    const char *sStateName;
    SME_STATE_TYPE_E nStateType;
    struct SME_STATE_T_TAG *pParent;
#if SME_CPP
    SME_EVENT_HANDLER_T pfnFunc;
    /* EntryFunc | CondFunc in C++ version*/
#else
    void *pfnFunc;
    /* EntryFunc | CondFunc | CompState for SME_STYPE_SUB | 
       Region app table for SME_STYPE_ORTHO_COMP in C version */
#endif
    SME_EVENT_HANDLER_T pfnExitFunc;
    SME_EVENT_TABLE_T *EventTable;
    /* Event Table or SME_REGION_CONTEXT_T table 
       for orthogonal state in C version. */
#if SME_CPP
    struct SME_STATE_T_TAG *pCompState;
    /* CompState for SME_STYPE_SUB in C++ version */
#endif
};
typedef struct SME_STATE_T_TAG SME_STATE_T;

typedef struct SME_EVENT_T_TAG
{
    SME_EVENT_ID_T nEventID;
    SME_UINT32 nSequenceNum;
    struct SME_EVENT_T_TAG *pNext; 
    /* Provide 2 data formats: integer or pointer */
    union SME_EVENT_DATA_T Data;
#if SME_CPP
    struct SME_APP_T *pDestApp; /* The destination application. */ 
#else
    struct SME_APP_T_TAG *pDestApp; /* The destination application. */ 
#endif
    void* pPortInfo; /* Point to a destination port information data. */
    SME_INT32 nOrigin :8; /* An internal event or an external event */
    SME_INT32 nCategory :8; /* Category of this event. */
    SME_INT32 nDataFormat :8; /* Flag for this event. */
    SME_INT32 bIsConsumed :8; /* Is consumed. */
}SME_EVENT_T,*SME_EVENT_PT;

/**** Event Handler *****/
#if SME_CPP
    struct SME_APP_T;
    typedef int (SME_APP_T::*SME_EVENT_HANDLER_T)
                (struct SME_APP_T *, SME_EVENT_T *); 
/* SME_NULL , SME_NULL_GUARD and SME_NULL_ACTION define to member function.*/
#define SME_NULL_STATE NULL
#define SME_INTERNAL_TRAN NULL
#else
    struct SME_APP_T_TAG;
    typedef int (* SME_EVENT_HANDLER_T)
                (struct SME_APP_T_TAG *, SME_EVENT_T *); 
#define SME_NULL NULL
#define SME_NULL_GUARD SME_NULL
#define SME_NULL_ACTION SME_NULL
#define SME_NULL_STATE SME_NULL
#define SME_INTERNAL_TRAN SME_NULL
#endif
    typedef SME_EVENT_HANDLER_T SME_TRAN_GUARD_T;
#define SME_BEGIN_STATE_DEF(_state, _type, _parent, _f1, _f2) \
SME_STATE_T _HandlerClass::SME_STATE_REF(_state) = \
{
    SME_STRINGIZE(_state), _type, &_HandlerClass::SME_STATE_REF(_parent), 
      (SME_EVENT_HANDLER_T)&_HandlerClass::_f1, 
      (SME_EVENT_HANDLER_T)&_HandlerClass::_f2, 
      _HandlerClass::SME_STATE_EVT_TBL_REF(_state) }; \

SME_EVENT_TABLE_T _HandlerClass::SME_STATE_EVT_TBL_REF(_state)[] = \
{
#define SME_END_STATE_DEF \
{
    SME_INVALID_EVENT_ID, NULL, NULL, SME_NULL_STATE} \
};
#define SME_BEGIN_COMP_STATE_DEF(_state, _parent, _entry, _exit) \
SME_STATE_T _HandlerClass::SME_COMPSTATE_REF(_state) = \
{ SME_STRINGIZE(_state), SME_STYPE_COMP, &_HandlerClass::SME_STATE_REF(_parent), 
  (SME_EVENT_HANDLER_T)&_HandlerClass::_entry, 
  (SME_EVENT_HANDLER_T)&_HandlerClass::_exit, 
  _HandlerClass::SME_COMPSTATE_EVT_TBL_REF(_state) }; \
SME_EVENT_TABLE_T _HandlerClass::SME_COMPSTATE_EVT_TBL_REF(_state)[] = \
{
#define SME_BEGIN_ROOT_COMP_STATE_DEF(_root_state, _entry, _exit) \
SME_STATE_T C##_root_state::SME_STATE_REF(_root_state) = 
 { #_root_state, SME_STYPE_SUB, (SME_STATE_T*)NULL, 
   &_HandlerClass::SME_NULL_GUARD, &_HandlerClass::SME_NULL_ACTION, NULL, 
   &_HandlerClass::SME_COMPSTATE_REF(_root_state) }; \
SME_STATE_T C##_root_state::SME_COMPSTATE_REF(_root_state) = \
{ #_root_state, SME_STYPE_COMP, SME_NULL_STATE, 
   (SME_EVENT_HANDLER_T)&C##_root_state::_entry, 
   (SME_EVENT_HANDLER_T)&C##_root_state::_exit, 
   _HandlerClass::SME_COMPSTATE_EVT_TBL_REF(_root_state) }; \
SME_EVENT_TABLE_T C##_root_state::SME_COMPSTATE_EVT_TBL_REF(_root_state)[] = \
{

#define SME_BEGIN_SUB_STATE_DEF(_state, _parent) \
SME_STATE_T _HandlerClass::SME_STATE_REF(_state) = \
{ SME_STRINGIZE(_state), SME_STYPE_SUB, 
  &_HandlerClass::SME_STATE_REF(_parent), &_HandlerClass::SME_NULL_GUARD, 
  &_HandlerClass::SME_NULL_ACTION, _HandlerClass::SME_STATE_EVT_TBL_REF(_state), 
  &_HandlerClass::SME_COMPSTATE_REF(_state) }; \
SME_EVENT_TABLE_T _HandlerClass::SME_STATE_EVT_TBL_REF(_state)[] = \
{
#define SME_BEGIN_LEAF_STATE_DEF(_state, _parent, _entry, _exit) \
SME_BEGIN_STATE_DEF(_state, SME_STYPE_LEAF, _parent, _entry, _exit)

References

  1. Andrew S. Tanenbaum. Computer Networks.
  2. Samek M. Practical State Charts in C/C++: Quantum Programming for Embedded Systems [M]. CMP BOOKS, 2002.
  3. Barr, Michael. Programming Embedded Systems in C and C++. Oreilly & Associates [M], 1999.
  4. Duby, Carolyn. Class203: Implementing UML State Chart Diagrams. Proceedings of Embedded Systems Conference [C], Fall, San Francisco, 2001.
  5. Egon Borger, Alessandra Cavarra, Elvinia Riccobene. Modeling the Dynamics of UML State Machines.
  6. UML StateWizard http://www.intelliwizard.com/.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Alex_Intw
Software Developer (Senior)
United States United States
Alex "Question is more important than the answer."

Comments and Discussions

 
QuestionPurchase a license from Intelliwizard Pinmemberxwy13-Mar-12 21:03 
GeneralBoost Statechart PinmemberNemanja Trifunovic7-Jun-07 4:21 
GeneralRe: Boost Statechart PinmemberAlex_Intw7-Jun-07 5:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411022.1 | Last Updated 7 Jun 2007
Article Copyright 2007 by Alex_Intw
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid