Click here to Skip to main content
15,881,709 members
Articles / Mobile Apps

Develop embedded systems based on UML state machines

Rate me:
Please Sign up or sign in to vote.
3.88/5 (9 votes)
1 Jun 2005CPOL3 min read 80.9K   1.3K   37   18
This article discovers how to develop and simulate cross-platform embedded systems using the UML State Machine Wizard.

Sample Image

Figure 1: The State Tree of PowerUpDown Application in Running Mode

Introduction

This article discovers how to develop and simulate cross-platform embedded systems using UML State Machine Wizard.

Background

Embedded systems are some special purpose computers that are used inside of devices. Embedded systems generally use micro controllers that contain many functions of a computer on a single device.

Embedded systems have to tightly work together with special hardware. They have to respond to external interactions in a predetermined amount of time. Usually embedded systems are real time.

Many embedded system applications are natural candidates for being organized as a state machine. A program that must sequence a series of actions, or handle inputs differently depending on what state it's in, is often best implemented as a state machine.

Thus most embedded systems support state machine based design where multiple events can be received in a single state. The next state is determined by the contents of the received event. State machines provide a very flexible mechanism to handle asynchronous event interactions. The flexibility comes with its own complexities.

Visual C++ is a powerful software developing tool. However it aims at developing Windows-specific applications. UML State Machine Wizard acts as a Visual C++ add-in, which provides a UML (Unified Modeling Language) state machine programming mechanism in portable standard C for embedded systems developing and simulating in Visual C++ developer studio. After simulating and debugging, developer can move the program to a destination working environment with little or no extra investment or effort.

Using the code

There are a number of ways to show state machines, from simple tables through graphically animated illustrations. State Machine Wizard shows and organizes state machines in two ways: state tree and state chart. State Machine Wizard defines a set of specific macros as state machine mapping data. These macros map to state enumerations, event handler function declarations, event handler table for a state, state tree definition and application variable definition. In the following source file PowerUpDown.c, State Machine Wizard generates the following macros to define the PowerUpDown application:

SME_BEGIN_STATE_DEF(PowerUpDown,PowerUpDown)
    /*{{SME_STATE_DEF(PowerUpDown,PowerUpDown)*/
    SME_STATE_ENTRY_FUNC(PowerUpDownEntry)
    SME_STATE_EXIT_FUNC(PowerUpDownExit)
    SME_ON_EVENT(EVENT_KEY_LEFTSOFT, 
        OnPowerUpDownEVENT_KEY_LEFTSOFT,SME_INTERNAL_TRAN)
    SME_ON_EVENT(EVENT_KEY_RIGHTSOFT,
        OnPowerUpDownEVENT_KEY_RIGHTSOFT,SME_INTERNAL_TRAN)
    /*}}SME_STATE_DEF*/
SME_END_STATE_DEF

SME_BEGIN_STATE_DEF(PowerUpDown,PowerDown)
    /*{{SME_STATE_DEF(PowerUpDown,PowerDown)*/
    SME_STATE_ENTRY_FUNC(PowerDownEntry)
    SME_STATE_EXIT_FUNC(PowerDownExit)
    SME_ON_EVENT(EVENT_POWER_UP,NULL,PowerUp)
    /*}}SME_STATE_DEF*/
SME_END_STATE_DEF
SME_BEGIN_STATE_DEF(PowerUpDown,PowerUp)
    /*{{SME_STATE_DEF(PowerUpDown,PowerUp)*/
    SME_STATE_ENTRY_FUNC(PowerUpEntry)
    SME_STATE_EXIT_FUNC(PowerUpExit)
    SME_ON_EVENT(EVENT_KEY_POWER,NULL,PowerDown)
    /*}}SME_STATE_DEF*/
SME_END_STATE_DEF
SME_BEGIN_STATE_DEF(PowerUpDown,Idle)
    /*{{SME_STATE_DEF(PowerUpDown,Idle)*/
    SME_STATE_ENTRY_FUNC(IdleEntry)
    SME_STATE_EXIT_FUNC(IdleExit)
    SME_ON_EVENT(EVENT_OPEN_MENU_MAIN,OnIdleEVENT_OPEN_MENU_MAIN,ImageSurf)
    SME_ON_EVENT(EVENT_OPEN_MENU_LANG,OnIdleEVENT_OPEN_MENU_LANG,MenuSurf)
    SME_ON_EVENT(EVENT_KEY_0,OnIdleEVENT_KEY_0,DigitInput)
    SME_ON_EVENT(EVENT_KEY_1,OnIdleEVENT_KEY_1,DigitInput)
    SME_ON_EVENT(EVENT_KEY_2,OnIdleEVENT_KEY_2,DigitInput)
    SME_ON_EVENT(EVENT_KEY_3,OnIdleEVENT_KEY_3,DigitInput)
    SME_ON_EVENT(EVENT_KEY_4,OnIdleEVENT_KEY_4,DigitInput)
    SME_ON_EVENT(EVENT_KEY_5,OnIdleEVENT_KEY_5,DigitInput)
    SME_ON_EVENT(EVENT_KEY_6,OnIdleEVENT_KEY_6,DigitInput)
    SME_ON_EVENT(EVENT_KEY_7,OnIdleEVENT_KEY_7,DigitInput)
    SME_ON_EVENT(EVENT_KEY_8,OnIdleEVENT_KEY_8,DigitInput)
    SME_ON_EVENT(EVENT_KEY_9,OnIdleEVENT_KEY_9,DigitInput)
    SME_ON_EVENT(EVENT_ON_TIMER,OnIdleEVENT_ON_TIMER,SME_INTERNAL_TRAN)
    /*}}SME_STATE_DEF*/
SME_END_STATE_DEF
SME_BEGIN_STATE_DEF(PowerUpDown,MenuSurf)
    /*{{SME_STATE_DEF(PowerUpDown,MenuSurf)*/
    SME_STATE_ENTRY_FUNC(MenuSurfEntry)
    SME_STATE_EXIT_FUNC(MenuSurfExit)
    SME_ON_EVENT(EVENT_MENU_EXIT,NULL,Idle)
    SME_ON_EVENT(EVENT_MENU_SEL,OnMenuSurfEVENT_MENU_SEL,Function)
    /*}}SME_STATE_DEF*/
SME_END_STATE_DEF
SME_BEGIN_STATE_DEF(PowerUpDown,Function)
    /*{{SME_STATE_DEF(PowerUpDown,Function)*/
    SME_STATE_ENTRY_FUNC(FunctionEntry)
    SME_STATE_EXIT_FUNC(FunctionExit)
    SME_ON_EVENT(EVENT_DLG_OK,OnFunctionEVENT_DLG_OK,Idle)
    SME_ON_EVENT(EVENT_DLG_CANCEL,NULL,Idle)
    /*}}SME_STATE_DEF*/
SME_END_STATE_DEF
SME_BEGIN_STATE_DEF(PowerUpDown,DigitInput)
    /*{{SME_STATE_DEF(PowerUpDown,DigitInput)*/
    SME_STATE_ENTRY_FUNC(DigitInputEntry)
    SME_STATE_EXIT_FUNC(DigitInputExit)
    SME_ON_EVENT(EVENT_EDIT_OK,OnDigitInputEVENT_EDIT_OK,Function)
    /*}}SME_STATE_DEF*/
SME_END_STATE_DEF
SME_BEGIN_STATE_DEF(PowerUpDown,ImageSurf)
    /*{{SME_STATE_DEF(PowerUpDown,ImageSurf)*/
    SME_STATE_ENTRY_FUNC(ImageSurfEntry)
    SME_STATE_EXIT_FUNC(ImageSurfExit)
    SME_ON_EVENT(EVENT_IMAGE_EXIT,NULL,Idle)
    SME_ON_EVENT(EVENT_IMAGE_FUNC,OnImageSurfEVENT_IMAGE_FUNC,Function)
    SME_ON_EVENT(EVENT_IMAGE_OPEN,OnImageSurfEVENT_IMAGE_OPEN,MenuSurf)
    /*}}SME_STATE_DEF*/
SME_END_STATE_DEF
/*{{SME_STATE_STATETREE_SEPARATOR}}*/
SME_BEGIN_STATE_TREE_DEF(PowerUpDown)
    /*{{SME_STATE_TREE_DEF(PowerUpDown)*/
    SME_STATE(PowerUpDown,PowerUpDown,SME_INVALID_STATE,PowerDown)
    SME_STATE(PowerUpDown,PowerDown,0,-1)
    SME_STATE(PowerUpDown,PowerUp,0,Idle)
    SME_STATE(PowerUpDown,Idle,PowerUp,-1)
    SME_STATE(PowerUpDown,MenuSurf,PowerUp,-1)
    SME_STATE(PowerUpDown,Function,PowerUp,-1)
    SME_STATE(PowerUpDown,DigitInput,PowerUp,-1)
    SME_STATE(PowerUpDown,ImageSurf,PowerUp,-1)
    /*}}SME_STATE_TREE_DEF*/
SME_END_STATE_TREE_DEF
/*{{SME_DEC_IMP_SEPARATOR}}*/
SME_APPLICATION_DEF(PowerUpDown, "PowerUpDown")


/* The follows are macro definitions for 
   state machine data mappings in header file. */

#define SME_BEGIN_STATE_DECLARE(_app) \
    enum _app##_state_enum_t \
    {

#define SME_STATE_DECLARE(_state) _state, 

#define SME_MAX_STATE(_app)    _app##_max_state

#define SME_END_STATE_DECLARE };

////////////////
#define SME_ENTRY_FUNC_IDX    0
#define SME_EXIT_FUNC_IDX     1
#define SME_EVENT_HANDLER_FUNC_IDX    2

#define SME_BEGIN_STATE_DEF(_app,_state) \
static const SME_EVENT_TABLE_T _app##_state##_event_hdl_tbl[] \
={

#define SME_STATE_ENTRY_FUNC( _EntryFunc) \
{  SME_INVALID_EVENT_ID, _EntryFunc, 0},

#define SME_STATE_EXIT_FUNC( _ExitFunc) \
{  SME_INVALID_EVENT_ID, _ExitFunc, 0},

#define SME_ON_EVENT(_EventID, _Handler, _NewState) \
{  _EventID, _Handler, _NewState},

#define SME_END_STATE_DEF { SME_INVALID_EVENT_ID, 0, SME_INVALID_STATE}};

#define SME_BEGIN_STATE_TREE_DEF(_app) \
extern const SME_STATE_TREE_TABLE_T _app##_state_tree[] = \
{

#define SME_STATE(_app,_state,_state_parent,_def_substate) \
    {(SME_EVENT_TABLE_T *)_app##_state##_event_hdl_tbl, 
      _state,_state_parent,_def_substate},

#define SME_END_STATE_TREE_DEF };

#define SME_APPLICATION_DEF(_app,_app_name) \
    struct SME_APP_T _app##App = { \
    _app_name, NULL, NULL, 0, NULL, NULL, 
    _app##_state_tree, SME_INVALID_STATE};

/* Get application variable name. */
#define SME_GET_APP_VAR(_app) _app##App

/* Declare application variable that has external linkage. */
#define SME_DEC_EXT_APP_VAR(_app) extern SME_APP_T _app##App;

//

The figure 1 shows the State Tree tab window in running mode. App project consists of the DialogCtrl, MenuCtrl and PowerUpDown applications. PowerUpDown application is comprised of (PowerUp (Idle, MenuSurf, Function), PowerDown) states.

The State Chart gives you a "birds'-eye view" of your application's logical structure and flow. It graphically constructs the state hierarchy, with child states nested within their parent state. Another of State Chart's major advantage over the State Tree is that it displays every state's transitions, in the form of arrows from one state to another state.

Sample Image

Figure 2:The State Chart of PowerUpDown Application

There are two threads in developing embedded system applications, one thread is application developing. The other thread is simulator developing. On each developing thread, we can divide it to the following three stages:

  • Modeling stage
  • Developing/coding stage
  • Simulating/debugging stage

Image 3

Figure 3: The Developing Stages

After simulating and debugging on the Windows platform, the developer can move the program to a destination working environment with little or no extra investment or effort.

License

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


Written By
Web Developer
China China
Jerome. (Free to speak, free to use.)

Comments and Discussions

 
QuestionPurchase a license from Intelliwizard Pin
xwy12-Mar-12 17:50
xwy12-Mar-12 17:50 
GeneralOpen engine source code Pin
Jerome_D19-Apr-06 20:25
Jerome_D19-Apr-06 20:25 
GeneralRe: Open engine source code Pin
xwy12-Mar-12 17:35
xwy12-Mar-12 17:35 
GeneralMultiThreaded Operation Pin
superfrigee28-Dec-05 17:52
superfrigee28-Dec-05 17:52 
GeneralRe: MultiThreaded Operation Pin
Jerome_D30-Dec-05 2:14
Jerome_D30-Dec-05 2:14 
GeneralGood Add In! Pin
cynew18-Sep-05 22:25
cynew18-Sep-05 22:25 
GeneralRe: Good Add In! Pin
Member 228503228-Sep-05 18:15
Member 228503228-Sep-05 18:15 
GeneralLOST!! Pin
WREY17-Sep-05 7:25
WREY17-Sep-05 7:25 
GeneralYou have to click Add-in CHECKBOX to load Wizard Pin
Jerome_D18-Sep-05 17:38
Jerome_D18-Sep-05 17:38 
GeneralRe: You have to click Add-in CHECKBOX to load Wizard Pin
WREY18-Sep-05 18:16
WREY18-Sep-05 18:16 
GeneralWay to show state tree and state chart Pin
Jerome_D19-Sep-05 4:28
Jerome_D19-Sep-05 4:28 
GeneralRe: LOST!! Pin
iloverockbest7-Oct-05 15:51
iloverockbest7-Oct-05 15:51 
QuestionCan this class show several curve at the same time? Pin
OilieLuo7-Aug-05 21:37
OilieLuo7-Aug-05 21:37 
AnswerRe: Can this class show several curve at the same time? Pin
OilieLuo7-Aug-05 21:39
OilieLuo7-Aug-05 21:39 
GeneralDoesn't work with German VC6 Sp5 Pin
Gunnar Bolle1-Jun-05 2:36
Gunnar Bolle1-Jun-05 2:36 
GeneralRe: Doesn't work with German VC6 Sp5 Pin
Jerome_D1-Jun-05 15:27
Jerome_D1-Jun-05 15:27 
GeneralInteresting Pin
juggler1-Jun-05 0:48
juggler1-Jun-05 0:48 
GeneralRe: Interesting Pin
Jerome_D1-Jun-05 15:44
Jerome_D1-Jun-05 15:44 
Hi, Juggler

Thank you for your comment. I answer your question blow your questions:

(a) there is no support here for asynchronous state machines and
This wizard does support asynchronous service call / events. You could get more information about the following functions in Help file.

SmePostEvent()
AgtPostExtEvent()
AgtPostServiceCall()
AgtSendServiceCall()


(b) the code is C
Yes. Portable (Cross-platform) standard C is good for embedded systems.

(c) the boost equivalent for C++ is boost::fsm, originally in the boost::mpl example from release 1_32_0 but now rather extended & improved, if still a bit of a git to use.

The entry function of state machine engine is
SmeRun()

You could get more detail information by www.intelliwizard.com.


Jerome

Jerome. An embedded system developer.

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

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