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.
State Machines are most commonly used when programming user interfaces. When creating a user interface, different user actions send the user interface into different processing segments. Each of these segments will act as states in the State Machine.
For every inch of paper there is a single letter printed on it–either the letter 'a' or the letter 'b'. The circles are “states” that the machine can be in. The arrows are the transitions. So, if you are in state s and read an 'a', you'll transition to state q.
In UML modeling, a guard condition is a boolean condition that is evaluated when a transition initiates. A transition with a guard condition occurs when the guard condition is evaluated to be true.
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_transitions()
function as it is trivial.
That's the way I do state machines for years.
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); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With