Create an Account
username: password:
 
  MemeStreams Logo

Writing Efficient State Machines in C

search

Neoteric
Picture of Neoteric
Neoteric's Pics
My Blog
My Profile
My Audience
My Sources
Send Me a Message

sponsored links

Neoteric's topics
Arts
  Music
   Blues
   Country
   Rap & Hip Hop
  TV
Business
Games
Health and Wellness
  Fitness
  Medicine
  Nutrition
Cooking
Entertaining
Holidays
Miscellaneous
  MemeStreams
Current Events
  War on Terrorism
Recreation
  Bicycling
  Camping and Hiking
Local Information
  Food
  United States
   District of Columbia
    Events in Washington D.C.
    News for Washington D.C.
   Maryland
Science
  Chemistry
  Math
  Physics
Society
  Politics and Law
   Surveillance
   Intellectual Property
Technology
  Computer Security
  Cyber-Culture
  Linux
  Software Development
  High Tech Developments

support us

Get MemeStreams Stuff!


 
Writing Efficient State Machines in C
Topic: Software Development 5:47 pm EDT, Apr  1, 2010

One common way of conquering difficult software design problems is to use a state machine. First you figure out all the states the software can be in. Then you determine all the inputs to the state machine—all the events that can cause the state machine to take some action or to change states. Finally you determine the state machine outputs—all the actions that the state machine can perform.

When your state machine design is done, you'll have a list of states, a list of events (inputs), and a set of action procedures for each state that describe what the state machine does for each event (outputs).

There are two ways to code a state machine in C. One way uses a set of nested switch statements. The outer switch has a case for each possible state. Each of these outer cases has an inner switch with a case for each possible event. The actual code that gets selected performs the actions for that state/event. Alternately, the outer switch could have a case for each event, and the inner switch could have a case for each state.

Another more concise way of coding is to use a lookup table. First, number all your states consecutively, starting with 0—an enum is a convenient way to do this. Do the same for your events. Then make up a set of tables, one table per state. Each table has one entry per event, in the same order as the event enum. Then the entire set of tables is arranged in the same order as the state enum. Each item in a table is the function to execute to perform the action for that particular event in that particular state.

The listing below is an example with three states and two events, and therefore six action procedures.

/* Define the states and events. If your state machine program has multiple
source files, you would probably want to put these definitions in an "include"
file and #include it in each source file. This is because the action
procedures need to update current_state, and so need access to the state
definitions. */

enum states { STATE_1, STATE_2, STATE_3, MAX_STATES } current_state;
enum events { EVENT_1, EVENT_2, MAX_EVENTS } new_event;

/* Provide the fuction prototypes for each action procedure. In a real
program, you might have a separate source file for the action procedures of
each state. Then you could create a .h file for each of the source files,
and put the function prototypes for the source file in the .h file. Instead
of listing the prototypes here, you would just #include the .h files. */

void action_s1_e1 (void);
void action_s1_e2 (void);
void action_s2_e1 (void);
void action_s2_e2 (void);
void action_s3_e1 (void);
void action_s3_e2 (void);
enum events get_new_event (void);

/* Define the state/event lookup table. The state/event order must be the
same as the enum definitions. Also, the arrays must be completely filled -
don't leave out any events/states. If a particular event should be ignored in
a particular state, just call a "do-nothing" function. */

void (*const state_table [MAX_STATES][MAX_EVENTS]) (void) = {

{ action_s1_e1, action_s1_e2 }, /* procedures for state 1 */
{ action_s2_e1, action_s2_e2 }, /* procedures for state 2 */
{ action_s3_e1, action_s3_e2 } /* procedures for state 3 */
};

/* This is the heart of the state machine - where you execute the proper
action procedure based on the new event you have to process and your current
state. It's important to make sure the new event and current state are
valid, because unlike "switch" statements, the lookup table method has no
"default" case to catch out-of-range values. With a lookup table,
out-of-range values cause the program to crash! */

void main (void)
{
new_event = get_new_event (); /* get the next event to process */

if (((new_event >= 0) && (new_event < MAX_EVENTS))
&& ((current_state >= 0) && (current_state < MAX_STATES))) {

state_table [current_state][new_event] (); /* call the action procedure */

} else {

/* invalid event/state - handle appropriately */
}
}

/* In an action procedure, you do whatever processing is required for the
particular event in the particular state. Among other things, you might have
to set a new state. */

void action_s1_e1 (void)
{
/* do some processing here */

current_state = STATE_2; /* set new state, if necessary */
}

void action_s1_e2 (void) {} /* other action procedures */
void action_s2_e1 (void) {}
void action_s2_e2 (void) {}
void action_s3_e1 (void) {}
void action_s3_e2 (void) {}

/* Return the next event to process - how this works depends on your
application. */

enum events get_new_event (void)
{
return EVENT_1;
}

sweet.

--timball

Writing Efficient State Machines in C



 
 
Powered By Industrial Memetics
RSS2.0