Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile

The StateWizard VC++ Add-in and Engine with Source Code

4.73/5 (24 votes)
26 Mar 2009CPOL12 min read 1   2.8K  
A cross-platform state-oriented application framework and a ClassWizard-like round-trip UML dynamic modeling/development tool that runs in popular IDEs. Aims at providing concurrent, distributed, and real-time application development tools for Win32/Linux

Introduction

In an environment where software systems are more and more complex, concurrent, and real-time oriented, the choice of modeling languages and tools becomes the success key for many projects.

This article introduces a cross-platform state-oriented application framework using standard C++/C for Win32/Linux and a ClassWizard-like round-trip UML dynamic modeling / development tool: StateWizard.

Points of Interest

The following table lists a wide range of techniques written for this project:

  1. Visual Studio add-in development for VS2003 or VS2005 using DTE
  2. COM development
  3. Asynchronous function call
  4. Cross-platform OS-related library
  5. Product quality state machine engines
  6. Win32 map file analysis

What is New?

UML: The Standard

The Unified Modeling LanguageTM - UML - is OMG's most-used specification and the way the world models not only application structure, behavior, and architecture, but also business processes and data structures.[1]

UML dynamic views are used to express and model the behavior of a system over time, presented through state machines, sequences, and activity diagrams.

State machine diagrams capture the behavior of a software system. State machines can be used to model the behavior of a class, subsystem, or an entire application. They also provide an excellent way of modeling communications with external entities via a protocol or event-based system.

Sequence diagrams are used to display the interaction between users, screens, objects, and entities within the system. They provide a sequential map of messages passing between objects over time.

Why UML StateWizard?

You may ask why UML StateWizard, while there are already many good UML tools such as Rational Rose, VisualState, and others. Our answer is:

  • StateWizard is a ClassWizard-like, simple and efficient IDE integrated tool
  • StateWizard is a full featured UML tool [2]
  • StateWizard is based on sound and optimized notions, implementation choices, and data structures
  • StateWizard has many useful "miscellaneous" features

1. A ClassWizard-like, Simple and Efficient IDE Integrated Tool

When developing the StateWizard, we kept in mind to offer an intuitive and easy to use solution:

  • Just like Microsoft Visual C++ ClassWizard, StateWizard runs inside the integrated development environment. No need to switch between tools for design/development, while many UML modeling tools run as standalone applications.
  • No intermediate modeling file, directly build UML diagrams from a set of specific macros and flags in the source code.
  • StateWizard rapidly builds applications with state machine based frameworks. It efficiently codes state charts directly in platform-independent standard C/C++.
  • StateWizard provides state tracking, simulation, and debugging for embedded system development.

The UML StateWizard supports the following IDEs:

  • Visual C++ 6.0
  • eMbedded Visual C++ 4.0
  • Visual Studio 2003
  • Visual Studio 2005

2. A Full-featured UML Tool

Some CASE tools allow the user to generate code from a set of specifications. Nevertheless, sometimes the generated code might not be very useful as it may be bulky and hard to understand for the designer. The StateWizard presents this solution:

  • UML diagram support: The StateWizard supports nine diagrams that make up UML state machines. It supports state tree and state chart drawing.
  • Forward engineering: The StateWizard UML tool does not have its use limited to just a pictorial depiction of diagrams. Because the structure of the system defined by the diagram is translated by a developer into actual source code, the StateWizard bridges this step by generating the source code in a state machine framework with the methods stubbed out. Developers can take up this stub code and fill in with the actual code. This characteristic of automating the generation of source code is called forward engineering.
  • Reverse engineering: Reverse engineering is exactly the opposite of forward engineering. In reverse engineering, StateWizard loads all the files of the application/system, identifies state relationships among applications, and essentially reconstructs the entire state machine structure along with all the relationships.
  • Round-trip engineering: Another useful feature apart from forward and reverse engineering is round-trip engineering. Forward and reverse engineering are essentially one-off activities that take input and generate the required output. Round-trip engineering extends these features. An important rule in software design is that no design remains unchanged. This is as true for small systems as it is for large systems. During development, the design structure defined in the UML model does undergo changes to incorporate physical differences in the implementation that may not have been envisaged during the design. It becomes very difficult to keep the design of the system synchronized with the changes in the source code. The round-trip engineering feature enables the UML tool to synchronize the model with the changes in the application code. The StateWizard tends to enforce the UML tool's capability of real-time synchronizing its model according to the modification in the code part. For example, developers can visually do a drag-and-drop operation in the state chart diagram, and subsequently the source code would change as well; to the contrary, developers may directly rectify the code part while modification will be automatically shown in the state chart diagram. It results in the StateWizard serving as a bridge between the state chart diagram and the source code.
  • Documentation: The StateWizard provides some way for the designer to document the design decisions in the diagrams. The designer may save the state chart as a BMP file and save the state tree as a text file.

3. StateWizard is Based on Sound and Optimized Notions and Implementation Choices

In addition to its innovative notions and concepts such as application and ports, the StateWizard was designed with optimal data structures and implementation choices guaranteeing efficient application code generation and round trip engineering. Among its features, we can state:

The State Chart

The State Chart models embedded systems without heavyweight, expensive CASE tools. The State Chart gives you a "bird's-eye view" of your application's logical structure and flow. It graphically constructs the state hierarchy, with child states nested within their parent mode. Another of State Chart's major advantages over the State Tree is that it displays every state's transitions in the form of arrows from one state to another state. If a developer selects a state or a transition, and then right clicks the mouse, the StateWizard will provide an action list by a menu depending on the selected state or the transition.

Screenshot - 1StateChartPlayer24.JPG

Figure: The State Chart

The State Tree

The State Tree is a state machine programmer's assistant, located in the VC workspace tab window. While coding, it will provide a state machine framework. It makes it easy for developers to do certain routing tasks such as creating a state machine application, creating a state hierarchy, defining an entry function and an exit function for a state, and defining event handlers. While running, it is a state tracker for all active applications. If a developer selects a state tree item and then right clicks the mouse, the StateWizard will provide an action list by a menu depending on the selected project, the application, or the state.

Screenshot - State_Tree_Pseudo.jpg

Figure: The State Tree

How the StateTree and StateChart Support Reverse Engineering

There is no additional state machine information besides C/C++ source code. How do the StateTree and StateChart support reverse engineering? Just like the Visual C++ ClassWizard, the StateWizard defines a set of macros to construct state machines, define states, sub-states, declare event handlers and state transitions.

For example, the following C++ macro defines a state machine named Player with the following states:

  • Player (PowerDown, PowerUp (Playing,Pause))

and state transitions:

  • (EXT_EVENT_ID_POWER, PowerDown -> PowerUp, OnPowerDownEXT_EVENT_ID_POWER)
  • (EXT_EVENT_ID_POWER, PowerUp -> PowerDown, OnPowerUpEXT_EVENT_ID_POWER)
  • (EXT_EVENT_ID_PAUSE_RESUME, Playing -> Pause, OnPlayingEXT_EVENT_ID_PAUSE_RESUME)
  • (EXT_EVENT_ID_PAUSE_RESUME, Pause -> Playing, OnPauseEXT_EVENT_ID_PAUSE_RESUME)
C++
SME_HANDLER_CLASS_DEF(Player)
C++
SME_BEGIN_STATE_DEF(Player,Player)
   /*{{SME_STATE_DEF(Player,Player)*/
   SME_STATE_ENTRY_FUNC(PlayerEntry)
   SME_STATE_EXIT_FUNC(PlayerExit)
   /*}}SME_STATE_DEF*/
   SME_END_STATE_DEF
C++
SME_BEGIN_STATE_DEF(Player,PowerDown)
   /*{{SME_STATE_DEF(Player,PowerDown)*/
   SME_STATE_ENTRY_FUNC(PowerDownEntry)
   SME_STATE_EXIT_FUNC(PowerDownExit)
   SME_ON_EVENT(EXT_EVENT_ID_POWER,OnPowerDownEXT_EVENT_ID_POWER,PowerUp)
   /*}}SME_STATE_DEF*/
   SME_END_STATE_DEF
C++
SME_BEGIN_STATE_DEF(Player,PowerUp)
   /*{{SME_STATE_DEF(Player,PowerUp)*/
   SME_STATE_ENTRY_FUNC(PowerUpEntry)
   SME_STATE_EXIT_FUNC(PowerUpExit)
   SME_ON_EVENT(EXT_EVENT_ID_POWER,OnPowerUpEXT_EVENT_ID_POWER,PowerDown)
   /*}}SME_STATE_DEF*/
   SME_END_STATE_DEF
C++
SME_BEGIN_STATE_DEF(Player,Playing)
   /*{{SME_STATE_DEF(Player,Playing)*/
   SME_STATE_ENTRY_FUNC(PlayingEntry)
   SME_STATE_EXIT_FUNC(PlayingExit)
   SME_ON_EVENT(EXT_EVENT_ID_PAUSE_RESUME,OnPlayingEXT_EVENT_ID_PAUSE_RESUME,Pause)
   /*}}SME_STATE_DEF*/
   SME_END_STATE_DEF
C++
SME_BEGIN_STATE_DEF(Player,Pause)
   /*{{SME_STATE_DEF(Player,Pause)*/
   SME_STATE_ENTRY_FUNC(PauseEntry)
   SME_STATE_EXIT_FUNC(PauseExit)
   SME_ON_EVENT(EXT_EVENT_ID_PAUSE_RESUME,OnPauseEXT_EVENT_ID_PAUSE_RESUME,Playing)
   /*}}SME_STATE_DEF*/
   SME_END_STATE_DEF
C++
/*{{SME_STATE_STATETREE_SEPARATOR}}*/
C++
SME_BEGIN_STATE_TREE_DEF(Player)
   /*{{SME_STATE_TREE_DEF(Player)*/
   SME_STATE(Player,Player,SME_INVALID_STATE,PowerDown)
   SME_STATE(Player,PowerDown,0,-1)
   SME_STATE(Player,PowerUp,0,Playing)
   SME_STATE(Player,Playing,PowerUp,-1)
   SME_STATE(Player,Pause,PowerUp,-1)
   /*}}SME_STATE_TREE_DEF*/
   SME_END_STATE_TREE_DEF
C++
/*{{SME_DEC_IMP_SEPARATOR}}*/
C++
SME_APPLICATION_DEF(Player, "Player")

State Machine Running Environment

The design of real-time or embedded applications usually involves decomposing the application software into objects, some of which may implement finite state machines for the process or the system control. Examples of these control objects might be the call control classes within a telephone switching system, or the treatment control classes within a medical instrument. Finite state machines are reactive, event-driven control structures whose behavior is determined by a received event and the history of events that preceded it. Other non-reactive classes provide computational or data retrieval services, not requiring maintenance of a machine state or a history of stimuli to complete their functions.

In the StateWizard environment, these active classes implement state machines and can process input events. The StateWizard State Machine Engine manages these classes and acts as an event dispatcher.

State machine objects can work in an active state or an inactive state. The State Machine Engine dispatches events to active state machine objects only. Inactive state machine objects do not handle events.

The architecture of the StateWizard runtime environment is depicted in the following diagram, showing the application objects and threads running above the State Machine Engine. The RTOS virtual layer provides a generic interface for the common RTOS services such as semaphores, mutexes, and thread control. The service provider layer is the interface layer to lower level modules and hardware interfaces. A simulation or destination environment layer provides the interface to the target environment or to a simulation of that target environment. Simulation is often employed during software development when the real target hardware is not yet available, or when extensive debugging facilities are needed but are not available on the target.

Screenshot - Interaction.jpg

Figure: StateWizard Runtime Architecture

State Machine Threads

Several active state machine objects may run under a single thread context. A thread context identifies an independent execution thread, and contains a thread identifier, a group of objects, an internal event pool, and several event hook functions.

State Machine Application Framework

The StateWizard provides two application frameworks for state machine objects:

  • Standard Embedded C
  • Standard C++

For the standard C++ application framework, a state machine object is constructed by a C++ class.

State Machine Object Activation

To activate, a state machine object identifies itself to the State Machine Engine by calling the SmeActivateObj () function. The following sample creates a Player state machine object named Player1. Player1 runs under a separate thread whose entry function is AppThreadProc. The thread context is g_AppThreadContext.

C++
void* AppThreadProc(void *Param)
{
  // The second parameter (NULL) is the state machine Player1's parent.

  SmeActivateObj(&Player1,NULL);
  SmeRun();
}
SME_OBJ_DEF(Player1,Player)
SME_THREAD_CONTEXT_T g_AppThreadContext;
XTHREADHANDLE ThreadHandle = 0;
// Install thread local storage data functions.

XTlsAlloc();
SmeSetTlsProc(XSetThreadContext, XGetThreadContext);
// Initialize the engine

SmeInitEngine(&g_AppThreadContext);
// Install external event handler functions.
// They act as a plug-in of the state machine engine.

SmeSetExtEventOprProc(XGetExtEvent, XDelExtEvent, XPostThreadExtIntEvent, 
                      XPostThreadExtPtrEvent, XInitMsgBuf, XFreeMsgBuf);
int ret = XCreateThread(AppThreadProc, NULL, &AppThreadHandle);
// The second parameter is the parameter for the thread entry function.

The player control panel may post external events to the event queue of the running thread. The engine will dispatch them to the active application Player1.

C++
XPostThreadExtIntEvent(&g_AppThreadContext, EXT_EVENT_ID_POWER, 0, 0, 
                       NULL,0,SME_EVENT_CAT_OTHER);

State Machine Object Deactivation

De-activating a state machine object is done by calling the SmeDeactivateObj() function. The following statement de-activates the Player1 state machine object.

C++
SmeDeactivateObj(&Player1);

Service Providers

Sate machine applications may tightly co-work with lower layer (other modules) or hardware, which are called service providers. A service is formally specified by a set of primitives (operations) available to service users (applications). These primitives tell the service to perform some action, or report on an action taken by a peer component/entity. The service primitives are classified into four categories:

  • Request
  • Indication
  • Response
  • Confirm

[Computer Networks, Andrew S.Tanenbaum]. The request and confirm primitives can be implemented in the form of service calls. The indication and response primitives can be implemented in the form of external event posting.

Active state machine objects can communicate with service providers using one of the following mechanisms, to exchange information:

  1. Synchronous service calls. These synchronous service calls may block, returning control to the application when the operation completes. Since most real-time systems must respond to external events in a predetermined amount of time, synchronous service calls are not used.
  2. Asynchronous service calls. Asynchronous functions do not block, continuing execution and returning before the operation is completed.
  3. Pro-active event indications. These events are posted from a service component to a client component without any request. An example might be an event posted by a hardware interrupt service routine.

Platform-independent Embedded System Development

There are many different Real Time Operation Systems (RTOS) on the embedded system market. Each different RTOS provides a different API to access a set of common system services. The StateWizard RTOS Virtual Layer provides a platform independent adapter layer allowing state machine portability between different operating systems. We can move the application from one RTOS to another without changing the application code. The external event receiver in the RTOS Virtual Layer acts as a plug-in to the state machine engine.

Simulators

Simulators should be considered when:

  • Hardware is unavailable or expensive
  • Extensive debugging capabilities are needed

Simulators are one of several important categories of testing tools. They emulate the environment in which the software will eventually perform, and often incorporate useful debugging features. They also enable testers to more effectively control the test environment, and may save critical development resources when scarce target hardware must be shared between engineers.

Simulation allows commencement of software testing before a hardware prototype is available. It also scales with the size and complexity of the system, helping to identify and solve problems early in the development cycle when correction is still inexpensive.

In a simulation environment, developers can simulate service providers running on desktop platforms, for example, Windows or Linux. These simulated services have identical interfaces with the target service provider interfaces. When moving to the destination environment, it should take little effort to integrate state machine applications with the real environment after they have been tested in the simulation. Active applications may make service calls presented by the service providers, and may receive external events triggered by service providers through RTOS functions.

You May Apply StateWizard To:

  • State machines based Win32/WinCE programs development through window message hooking technology
  • Cross-platform embedded system modeling and simulation

The StateWizard Pro Engine with Product Quality

  • Hierarchical state machines
  • Support large state machine with hundreds of states through separating state tree definitions in several C/C++ files
  • State history information and history transitions
  • Guarded transitions on event handling
  • Conditional pseudo-states
  • Join pseudo-states
  • Multi-threaded orthogonal states
  • Built-in state timers; on state entry, starts the built-in timer automatically, stops it on state exit
  • Cross-platform event loop and OS-related API library for Linux/Win32

Download the StateWizard Pro here.

Licensing

You may download more information from here, the official site of the UML StateWizard open source project under LGPL license.

References

License

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