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

Develop embedded systems based on UML state machines

By , 1 Jun 2005
Rate this:
Please Sign up or sign in to vote.

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

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)

About the Author

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

Comments and Discussions

 
QuestionPurchase a license from Intelliwizard Pinmemberxwy12-Mar-12 17:50 
GeneralOpen engine source code PinmemberJerome_D19-Apr-06 20:25 
GeneralRe: Open engine source code Pinmemberxwy12-Mar-12 17:35 
GeneralMultiThreaded Operation Pinmembersuperfrigee28-Dec-05 17:52 
GeneralRe: MultiThreaded Operation PinmemberJerome_D30-Dec-05 2:14 
GeneralGood Add In! Pinmembercynew18-Sep-05 22:25 
GeneralRe: Good Add In! Pinmembernorus.celler28-Sep-05 18:15 
GeneralLOST!! PinmemberWREY17-Sep-05 7:25 
GeneralYou have to click Add-in CHECKBOX to load Wizard PinmemberJerome_18-Sep-05 17:38 
GeneralRe: You have to click Add-in CHECKBOX to load Wizard PinmemberWREY18-Sep-05 18:16 
GeneralWay to show state tree and state chart Pinmemberjerome_19-Sep-05 4:28 
GeneralRe: LOST!! Pinmemberiloverockbest7-Oct-05 15:51 
QuestionCan this class show several curve at the same time? PinmemberOilieLuo7-Aug-05 21:37 
AnswerRe: Can this class show several curve at the same time? PinmemberOilieLuo7-Aug-05 21:39 
GeneralDoesn't work with German VC6 Sp5 PinmemberGunnar Bolle1-Jun-05 2:36 
GeneralRe: Doesn't work with German VC6 Sp5 PinmemberJerome_1-Jun-05 15:27 
GeneralInteresting Pinsussjuggler1-Jun-05 0:48 
This is nice stuff, but the article that goes with the code is a bit short to explain what you are trying to do. More information about the code the wizard generates would be nice.
 
It's worth noting that
(a) there is no support here for asynchronous state machines and
(b) the code is C
(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.
GeneralRe: Interesting PinmemberJerome_1-Jun-05 15:44 

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 | Mobile
Web01 | 2.8.140415.2 | Last Updated 2 Jun 2005
Article Copyright 2005 by Jerome_D
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid