views:

1387

answers:

8

Hello,

C99

I am just wondering if anyone know of some good tutorials on the Internet for developing state machines. Or ebooks?

I am starting working on state machines and just need something general to get me started.

Many thanks,

A: 

This is all you need to know.

int state = 0;
while (state < 3)
{
    switch (state)
    {
     case 0:
      // Do State 0 Stuff
      if (should_go_to_next_state)
      {
       state++;
      }
      break;
     case 1:
      // Do State 1 Stuff    
      if (should_go_back) 
      {
       state--;
      }    
      else if (should_go_to_next_state) 
      {
       state++;
      }
      break;
     case 2:
      // Do State 2 Stuff    
      if (should_go_back_two) 
      {
       state -= 2;
      }    
      else if (should_go_to_next_state) 
      {
       state++;
      }
      break;
     default:
      break;
    }
}
ChaosPandion
I woud consider it better practice to explicitly set the state, but that's just me.
Chris Lutz
It would be event better practice to name the state. Let me fix that.
ChaosPandion
You've left out a lot, for example: substates; events, and event/state combinations; state transition diagrams; guards ("don't change state if"); state entry and state exit methods ("on exiting this state do the following method").
ChrisW
This is oversimplifying state machines, and not that great of an example.
X-Istence
Don't over complicate something that is very simple.
ChaosPandion
A guard is a condition that must be true in order to traverse a transition. Hmmm... that's a complex way of saying an if statement.
ChaosPandion
Sure, as a skeleton for what a basic state machine might look like this might suffice. But I think it's not quite "all you need to know". Also, you might want to make your state unsigned.
mrduclaw
+3  A: 

Real-Time Object-Oriented Modeling was fantastic (published in 1994 and now selling for as little as 81 cents, plus $3.99 shipping).

ChrisW
1 new from $60.20 and 24 used from $0.81. That's pretty humorous.
marcc
+4  A: 

State machines are not something that inherently needs a tutorial to be explained or even used. What I suggest is that you take a look at the data and how it needs to be parsed.

For example, I had to parse the data protocol for a Near Space balloon flight computer, it stored data on the SD card in a specific format (binary) which needed to be parsed out into a comma seperated file. Using a state machine for this makes the most sense because depending on what the next bit of information is we need to change what we are parsing.

The code is written using C++, and is available as ParseFCU. As you can see, it first detects what version we are parsing, and from there it enters two different state machines.

It enters the state machine in a known-good state, at that point we start parsing and depending on what characters we encounter we either move on to the next state, or go back to a previous state. This basically allows the code to self-adapt to the way the data is stored and whether or not certain data exists at all even.

In my example, the GPS string is not a requirement for the flight computer to log, so processing of the GPS string may be skipped over if the ending bytes for that single log write is found.

State machines are simple to write, and in general I follow the rule that it should flow. Input going through the system should flow with certain ease from state to state.

X-Istence
Just curious - how does a balloon get "near space"? Don't balloons need an atmosphere? Wouldn't you get to the point where it's hard/impossible to come back?
Chris Lutz
@Chris: Near Space is defined as anything above 60,000 ft, our balloon got to 92,999 ft. At some point the latex balloon starts to become so large because of the decompression (the gas keeps expanding the balloon) that the balloon pops, at which point the near space craft free-falls back to earth (we attach a parachute off course), see the linked Wiki for more information about our Near Space efforts and Google around, it is an absolutely awesome hobby!
X-Istence
That sounds like a wildly inefficient, ridiculously expensive, perhaps a bit wasteful, and completely awesome hobby.
Chris Lutz
Many powerful and important experiments have been run from balloon platforms, you have to compare costs with the those of launching an equivalent *orbiting* platform. By the time you get to circa 100,000 ft, your heat management problem is essential that of a spacecraft: conductive and convective heating/cooling are vanishing by comparison to radiation.
dmckee
@Chris: We had a budget of $2000 to work with, and we have so far successfully launched two balloons. The most expensive part was the helium to fill the latex balloons which were the second most expensive part.
X-Istence
+13  A: 

State machines are very simple in C if you use function pointers.

Basically you need 2 arrays - one for state function pointers and one for state transition rules. Every state function returns the code, you lookup state transition table by state and return code to find the next state and then just execute it.

int entry_state(void);
int foo_state(void);
int bar_state(void);
int exit_state(void);

/* array and enum below must be in sync! */
int (* state)(void)[] = { entry_state, foo_state, bar_state, exit_state};
enum state_codes { entry, foo, bar, end};

enum ret_codes { ok, fail, repeat};
struct transition {
    enum state_codes src_state;
    enum ret_codes   ret_code;
    enum state_codes dst_state;
};
/* transitions from end state aren't needed */
struct transition state_transitions[] = {
    {entry, ok,     foo},
    {entry, fail,   end},
    {foo,   ok,     bar},
    {foo,   fail,   end},
    {foo,   repeat, foo},
    {bar,   ok,     end},
    {bar,   fail,   end},
    {bar,   repeat, foo}};

#define EXIT_STATE end
#define ENTRY_STATE entry

int main(int argc, char *argv[]) {
    enum state_codes cur_state = ENTRY_STATE;
    enum ret_codes rc;
    int (* state_fun)(void);

    for (;;) {
        state_fun = state[cur_state];
        rc = state_fun();
        if (EXIT_STATE == cur_state)
            break;
        cur_state = lookup_transitions(cur_state, rc);
    }

    return EXIT_SUCCESS;
}

I don't put lookup_transition() function as it is trivial.

That's the way I do state machines for years.

qrdl
Nice... thanks for this.
jldupont
+1  A: 

Unfortunately, most of the articles on state machines are written for C++ or other languages that have direct support for polymorphism as it's nice to model the states in an FSM implementation as classes that derive from an abstract state class.

However, it's pretty easy to implement state machines in C using either switch statements to dispatch events to states (for simple FSMs, they pretty much code right up) or using tables to map events to state transitions.

There are a couple of simple, but decent articles on a basic framework for state machines in C here:

switch statement-based state machines often use a set of macros to 'hide' the mechanics of the switch statement (or use a set of if/then/else statements instead of a switch) and make what amounts to a "FSM language" for describing the state machine in C source. I personally prefer the table-based approach, but these certainly have merit, are widely used, and can be effective especially for simpler FSMs.

One such framework is outlined by Steve Rabin in "Game Programming Gems" Chapter 3.0 (Designing a General Robust AI Engine).

A similar set of macros is discussed here:

If you're also interested in C++ state machine implementations there's a lot more that can be found. I'll post pointers if you're interested.

Michael Burr
Thanks, they were good articles. I found one here also. http://en.wikipedia.org/wiki/Event_driven_finite_state_machine
robUK
+1  A: 

There is a lot of lesson to learn handcrafting state machines in C, but let me also suggest Ragel state machine compiler:

http://www.complang.org/ragel/

It has quite simple way of defining state machines and then you can generate graphs, generate code in different styles (table-driven, goto-driven), analyze that code if you want to, etc. And it's powerful, can be used in production code for various protocols.

Roman Khimov
+1  A: 

I made some google search about state machines in c . And found a link with some explanation very similar to what qrdl tried to explain .

The Link

Night Walker
+2  A: 

I prefer using function pointers over gigantic switch statements, but in contrast to qrdl's answer I normally don't use explicit return codes or transition tables.

Also, in most cases you'll want a mechanism to pass along additional data. Here's an example state machine:

#include <stdio.h>

struct state;
typedef void state_fn(struct state *);

struct state
{
    state_fn * next;
    int i; // data
};

state_fn foo, bar;

void foo(struct state * state)
{
    printf("%s %i\n", __func__, ++state->i);
    state->next = bar;
}

void bar(struct state * state)
{
    printf("%s %i\n", __func__, ++state->i);
    state->next = state->i < 10 ? foo : 0;
}

int main(void)
{
    struct state state = { foo, 0 };
    while(state.next) state.next(&state);
}
Christoph
Your `main` doesn't return a value . . . should it?
dreamlax
@dreamlax: C99 5.1.2.2.3: reaching the end of `main()` implicitly returns `0`
Christoph