3 * @author Tran Duy Khanh
7 * @brief Finite State Machine
10 /* Copyright: (c) 2007 CTU Dragons
11 * CTU FEE - Department of Control Engineering
12 * Contacts: Tran Duy Khanh <trandk1@fel.cvut.cz>
13 * License: GNU GPL v.2
17 \defgroup fsm Finite State Machines
19 Finite state machines/automatons (FSM) are used to control various
24 - \ref state_functions
29 \section fsm_general Introduction
31 FSMs are used to write applications that need to react on events. In
32 the simples cases it is sufficient to write such applications only by
33 combinations of switch and if statements. In other cases when the
34 number of events is higher than a small number and the response to
35 events differs depending on many conditions, such approach is usually
36 error prone, since the code becomes complicated. This library provides
37 a framework which makes programming such applications more easy.
39 The fundamental entity in this library is FSM. Every FSM is defined by
40 structure ::robo_fsm and a set of state functions. The state
41 functions are executed as a response to some events. The events can be
42 generated internally (see ::fsm_common_events), by another FSM or by
43 some other piece of code. There is exactly one "current" state
44 function at a given time. The goal of the current state functions is
45 to react to events. The reaction to an event can be represented by an
46 arbitrary piece of code that does something useful. It is also
47 possible to change the current state (function) of FSM (so called
48 state transition). Having several state functions, it is possible to
49 react differently on the same events depending on what is the current
52 Every FSM can be executed either in its dedicated threads or together
53 with other FSMs in a single thread. Which way is better for your
54 application depends on your needs. If the code in state functions may
55 take long time to execute and you need to react quickly to some
56 events, use the threaded FSMs and assign higher priority to threads
57 with real-time requirements and low priority to non-real-time threads
58 with long execution times.
60 On the other hand, having all FSMs running in a single thread may
61 simplify your application, because you do not have to deal with
62 concurrent execution. The price for this is, that response time to an
63 critical event may be too high.
65 It is also possible to have something in between the above two
66 approaches. You can have, for instance, real-time FSMs running in
67 their own high-priority threads and non-real-time FSMs, sharing a
68 single low-priority thread.
70 \section state_functions State Functions
72 The state function is a function taking a pointer to FSM structure as
73 an argument and returning an integer value. To make declaration of
74 state function easier, there is a macro FSM_STATE(). This macro
75 declares the state functions and also adds some code to conditionally
76 print debugging messages. Thanks to this macro, programmer can
77 concentrate on the real programming task and the complexity of
78 declaration is hidden.
80 The usual structure of a state function is one big switch
81 statement. The switch condition is the #FSM_EVENT macro, whose value
82 is the identifier of the event (see section \ref fsm_events) to be
83 handled. In the handling code you can execute whatever you want. If
84 there is some data associated with the event, it can be retrieved by
85 #FSM_EVENT_PTR or #FSM_EVENT_INT. Additionally, FSM infrastructure
86 provides some useful functions and macros. To work with time, you can
87 use FSM_TIMER(). To execute transition to another state, use
88 FSM_TRANSITION() or SUBFSM_TRANSITION() (see \ref subfsm). To send an
89 event to another FSM, use FSM_SIGNAL().
91 An example state function, whose only function is to wait 1 second
92 before entering \c another_state is shown here:
101 FSM_TRANSITION(another_state);
107 For the above to work, it is important to declare the macro @c FSM_<id>
108 before including header with event definition and fsm.h. See the note in \ref
109 fsm_events section. This means, that state functions for different
110 FSMs have to be declared in separate files.
112 \section fsm_events Events
114 An event is identified by an event identifier. This is a string
115 usually starting with @c EV_ prefix. Some data can be associated with
116 events. This data can be a pointer or integer typecasted to pointer.
118 Every FSM can handle so called common events (e.g. #EV_ENTRY,
119 see ::fsm_common_events) and also some additional events specific to
120 the FSM. Those additional events are declared only for a given FSM and
121 can be sent to that FSM from another place by the FSM_SIGNAL()
122 macro. To avid programming errors we have three requirements for
125 -# It is not possible to send an event to FSM, which didn't declare
126 it. This situation should produce compile-time error.
127 -# In a state function, an attempt to handle an event declared for
128 another FSM should also produce compile-time error.
129 -# If some event, which can be handled by the FSM, is omitted in the switch
130 command, we want to be warned.
132 These requirements are hard to achieve in plain C. Therefore,
133 additional events for FSMs are declared as a data structure in Python
134 and there is a Python script eventgen.py, which converts this definition to .h a
137 The event definition is a Python dictionary (associative array) called
138 @c events. Keys to this dictionary are the lowercase identifiers of
139 FSM. The value is another dictionary, which defines the events for
140 that FSM. The key is the event identifier and value is a comment. In
141 the example below, event for two FSMs called "tested" and "tester" are
142 defined. The "tested" FSM can handle additional events EV_PING and EV_OTHER and
143 "tester" FSM handles "EV_PONG".
145 \include example_ev.py
147 The script, which generates .c and .h source code is called
148 eventgen.py. In .h, there is one enum for each FSM with all events
149 this FSM can handle. The members of enums are not directly event identifiers,
150 but some internal identifiers starting with double underscore
151 (__). You should never use these identifiers directly in your
152 application. Then, there are macros, which translates the event
153 identifiers to internal event identifiers. Thanks to this, the above
154 requirements 1. and 2. are fulfilled. Requirement no. 3 is also
155 fulfilled because recent versions of GCC warns if some enum member is
156 not handled in switch statement (unless you use @c default statement).
158 @note You have to always include the generated header file with events before fsm.h.
159 If you do not do so, an error is generated.
161 @note In the source, where you define your state function, you have to
162 define macro @c FSM_<id>, where @c <id> is uppercase identifier of FSM
163 as defined in event definition. If you do not do so, you get a compilation error
164 on definition of state function. GCC generates this error message:
166 error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘FSM_XXX_not_defined’
169 \section fsm_usage Usage
171 To use FSMs provided by this library in your application, you need to
172 -# define additional event for your automatons (see section \ref fsm_events),
173 -# define state functions for your automatons (see section \ref
175 -# start execution of the automatons (every FSM executes in its own thread).
177 Definition of state functions usually starts with lines like this:
179 #define FSM_SOME_NAME // define which FSM state functions are to be declared here
180 #include "events.h" // include definition of additional events (generated from events.py)
183 FSM_STATE(test_state1) {
188 Initialization of an automaton looks like:
191 struct fsm_main_loop loop;
192 fsm_main_loop_init(&loop);
193 fsm_init(&fsm, "id_for_debug_massages", &loop);
194 fsm.state = &fsm_state_test_state1; // Initial state of the automaton
197 To start the FSM in its own thread do:
199 if (fsm_start(&loop, NULL) != 0) {
204 To start it in the current thread do:
206 fsm_main_loop(&loop);
209 \section subfsm Sub-Automatons
211 Sometimes, it may be useful to enter a state of sub-automaton and
212 return back to current state after this sub-automaton finishes its
213 task. You can enter the sub-automaton state by calling
214 SUBFSM_TRANSITION(). When the sub-automaton is done, call from some of
215 its state functions SUBFSM_RET(). Then the original state function
216 will be called with ::EV_RETURN.
218 Sub-automaton calling can be nested up to the level of 10.
230 #include <semaphore.h>
231 #include <sys/time.h>
233 #include "fsm_common_events.h"
237 * Type for FSM events
240 typedef struct fsm_event {
241 int id; /** Event identifier (e.g. EV_TIMER) */
242 void *data; /** Any data sent together with the event */
245 #ifndef __FSM_ALIASES_DEFINED
246 #define EV_NOEVENT __COMMON_EV_NOEVENT
247 #define EV_ENTRY __COMMON_EV_ENTRY
248 #define EV_EXIT __COMMON_EV_EXIT
249 #define EV_RETURN __COMMON_EV_RETURN
250 #define EV_TIMER __COMMON_EV_TIMER
255 struct fsm_main_loop {
256 pthread_t threadid; /**< Thread running the main loop or NULL. */
257 struct robo_fsm *fsm; /**< List of FSMs handled by this loop */
259 /** Main loop waits on this semaphore while it waits for an event. */
261 /** Pointer to FSM whose timer expires first or NULL on no
262 * timer is active. */
263 struct robo_fsm *first;
264 struct timespec now; /**< Time when an event occurred */
267 /** Event handler function for FSM.
270 typedef int (*robo_fsm_state_t)(struct robo_fsm *fsm);
272 #define FSM_EVENT_QUEUE_LEN 10
274 /** Set on event queue overrun, never zeroed. */
275 #define FSM_FLAG_EVENT_LOST 0x01
276 /** Set by fsm_exit() */
277 #define FSM_FLAG_FINISH 0x02
279 /** Structure describing FSM.
283 struct robo_fsm *next;
284 /** Main loop, which dispatches events for this FSM. */
285 struct fsm_main_loop *loop;
287 pthread_mutex_t send_mutex;
288 /** Ring-buffer for incomming events */
289 struct fsm_event events[FSM_EVENT_QUEUE_LEN];
290 /** Index in the @a events of the next event to be processed. */
292 /** Index in the @a events where to put events for this
293 * message. Protected by @a send_mutex */
296 struct timespec timer; /**< Time of next timer expiration */
298 /** Pointer to current state function. This function is called
299 * when an event occurs. */
300 robo_fsm_state_t state;
301 const char *state_name; /**< Name of the current state */
302 robo_fsm_state_t last_state; /**< Pointer to previous state function */
303 /** Stack of sub-automaton states for use by FCALL() and SUBFSM_TRANSITION(). */
304 const char *last_state_name; /**< Name of the last state */
305 robo_fsm_state_t fnc_stack[10];
306 /** Pointer to the top of fnc_stack */
307 robo_fsm_state_t *fnc_sp;
308 int debug_states; /**< Whether to print debug messages on state transitions. */
309 char *debug_name; /**< The name of automaton (printed in debug messages) */
311 * Pointer to transition callback function. This function is
312 * called whenever fsm changes state. This callback can be
313 * used to track/debug the state of FSM. @c fsm->state_name
314 * will contain the name of current state, @c fsm->last_state_name
315 * the name of last state.
317 void (*transition_callback)(struct robo_fsm *fsm);
324 void fsm_main_loop_init(struct fsm_main_loop *loop);
325 void fsm_init(struct robo_fsm *fsm, char *debug_name, struct fsm_main_loop *loop);
326 int fsm_start(struct fsm_main_loop *loop, pthread_attr_t *attr);
327 void fsm_exit(struct robo_fsm *fsm);
328 void fsm_destroy(struct robo_fsm *fsm);
329 void fsm_main_loop(struct fsm_main_loop *loop);
330 void __fsm_timespec_add_ms(struct timespec *ts, struct timespec *now, long ms);
331 void __fsm_timespec_invalidate(struct timespec *ts);
332 int __fsm_timespec_cmp(struct timespec *ts1, struct timespec *ts2);
336 /* FSM (Finite State Machine) */
338 int fsm_nop_state(struct robo_fsm *fsm);
341 * Returns string with the name of event submitted as parameter.
342 * @param ev Indetifier of the event
343 * @return The name of event or "undefined event!!!" if the @c ev
344 * doesn't refer to a valid event.
348 const char *fsm_event_str(fsm_event ev);
349 const char *fsm_common_event_str(fsm_event ev);
351 /** \name Return codes of state functions */
353 /** After return, FSM thread starts waiting for the new event. */
355 /** After return, current state function (fnc_act) will be immediately
356 * called again. Used by FSM_TRANSITION(). */
360 #define FSM_WAIT_FOREVER -1l
362 static inline void fsm_set_flags(struct robo_fsm *fsm, int flag_mask)
364 __sync_fetch_and_or(&fsm->flags, flag_mask);
367 static inline void __fsm_signal(struct robo_fsm *fsm, fsm_event event,
371 pthread_mutex_lock(&fsm->send_mutex);
372 fsm->events[fsm->ev_tail] = event;
373 new_tail = fsm->ev_tail + 1;
374 if (new_tail >= FSM_EVENT_QUEUE_LEN)
377 if (new_tail != fsm->ev_head) {
378 fsm->ev_tail = new_tail;
379 if (sem && fsm->loop)
380 sem_post(&fsm->loop->event_sent);
382 fsm_set_flags(fsm, FSM_FLAG_EVENT_LOST);
383 fprintf(stderr, "fsm %s: Event lost\n", fsm->debug_name);
385 pthread_mutex_unlock(&fsm->send_mutex);
389 * Sends an event to another FSM, which may run in another
390 * thread. Event sending is asynchronous, but each FSM has a buffer for
391 * several events. If this buffer is full, @a event_lost flag is set
392 * and the event is lost. This should never happen in a carefully
393 * designed application.
395 * @note This macro ensures that it is not possible to send an event
396 * to other FSM than the one for which it was declared. If you get
397 * compilation error, that @c __<FSM_ID>_<EVENT_ID> is not declared,
398 * it means the recipient doesn't handle this event.
401 * @param fsm_id Event recipient's ID.
402 * @param event Event ID to send.
403 * @param data Any data (pointer or typecasted int) sent together with
406 #define FSM_SIGNAL(fsm_id, event, data) \
408 fsm_event e = {__##fsm_id##_##event, data}; \
409 __fsm_signal(FSM_GET_BY_ID(fsm_id), e, true); \
413 * \def FSM_GET_BY_ID(fsm_id)
415 * Returns pointer to struct ::fsm identified by the id. This macro
416 * should be defined by the application, which uses fsm.h.
418 * @param fsm_id FSM indentifier. This is the uppercase variant of the
419 * string, which defines the FSM in definition of events in python
425 #define DBG_STATE() DBG_FSM_STATE(__FUNCTION__)
426 #define DBG_FSM_STATE(name) do { if (fsm->debug_states) printf("fsm %s: %s(%s)\n", fsm->debug_name, name, fsm_event_str(fsm->events[fsm->ev_head])); } while(0)
428 * Prints current event in a human readable form.
431 #define DBG_PRINT_EVENT(msg) printf("fsm %s %s %s: %s\n", fsm->debug_name, fsm->state_name, fsm_event_str(fsm->events[fsm->ev_head]), msg)
437 static inline void call_transition_callback(struct robo_fsm *fsm)
439 if (fsm->transition_callback != NULL &&
440 (fsm->last_state != (fsm)->state) &&
441 (fsm->events[fsm->ev_head].id == EV_ENTRY || /* FIXME: Is this line correct? */
442 fsm->events[fsm->ev_head].id == EV_RETURN)) {
443 fsm->transition_callback(fsm);
447 /**********************/
448 /* High level FSM API */
449 /**********************/
452 * Specifies state function visibility.
454 * If this macro is redefined from "" (empty) to static, then the
455 * state functions are declared as static.
457 #define FSM_STATE_VISIBILITY
459 #define ___fsm_func_name(fsm, state, suf) fsm_state_##fsm##_##state##suf
460 #define __fsm_func_name(fsm, state, suf) ___fsm_func_name(fsm, state, suf)
463 * Defines a state function for finite state machine. This function is
464 * called by FSM framework whenever some event occurs. The event can
465 * be read by using ::FSM_EVENT macro. In the function body, other @a
466 * FSM_xxx macros can be used to invoke state transition or set
467 * the timer. When no state transition is invoked, FSM waits
468 * for the next event, after the function returns. Then, after another
469 * event occurs, this state function is called again with that event.
471 * @note The body of state function is declared as void inline
472 * function. This function is called from state function stub, which
473 * contains debugging macros.
475 * The actual name of the function stub is @c fsm_state_<name> and the
476 * name of inline implementation is @c fsm_state_<name>_impl.
478 * @param name Name of the state.
482 #define FSM_STATE(name) \
483 static inline void __fsm_func_name(__FSM_NAME, name, _impl)(struct robo_fsm *fsm, int *__ret); \
484 FSM_STATE_VISIBILITY int __fsm_func_name(__FSM_NAME, name,)(struct robo_fsm *fsm) { \
486 DBG_FSM_STATE(#name); \
487 fsm->state_name = #name; \
488 call_transition_callback(fsm); \
489 __fsm_func_name(__FSM_NAME, name, _impl)(fsm, &ret); \
492 static inline void __fsm_func_name(__FSM_NAME, name, _impl)(struct robo_fsm *fsm, int *__ret)
494 #define FSM_STATE(name) error_FSM_XXX_not_defined
497 * Declares a prototype of state function defined later.
499 * @param name Name of state function.
502 #define FSM_STATE_DECL(name) \
503 FSM_STATE_VISIBILITY int __fsm_func_name(__FSM_NAME, name,)(struct robo_fsm *fsm)
505 #define FSM_STATE_DECL(name) error_FSM_XXX_not_defined
509 * Declares a prototype of state function of given FSM. This can be
510 * used to declare state function in header files (of other .c files)
511 * that the one with the state functions itself
514 * @param fsm_name Name of FSM
515 * @param name Name of state function.
517 #define FSM_STATE_FULL_DECL(fsm_name, name) \
518 int __fsm_func_name(fsm_name, name,)(struct robo_fsm *fsm)
521 * Sets FSM's one-shot timer. After the specified number of
522 * milliseconds elapses, ::EV_TIMER is generated, unless
523 * FSM_TIMER_STOP() is used. The timer is automatically stopped on
526 * @param ms Time to timer expiration in milliseconds.
529 #define FSM_TIMER(ms) \
530 if (FSM_EVENT != EV_EXIT) { \
531 __fsm_timespec_add_ms(&fsm->timer, &fsm->loop->now, (ms)); \
532 if (!fsm->loop->first || \
533 __fsm_timespec_cmp(&fsm->timer, \
534 &fsm->loop->first->timer) == -1) { \
535 fsm->loop->first = fsm; \
543 #define FSM_TIMER_STOP() __fsm_timer_stop(fsm)
545 void __fsm_timer_stop(struct robo_fsm *);
547 #ifndef __FSM_EVENT_ENUM
548 /* This macro is normally declared in automatically generated event
549 * header file. If fsm.h is included from other files, we fall back to
550 * fsm_common_events. If you get warning: "__FSM_EVENT_ENUM"
551 * redefined, it means that FSM_xxx definition of event is included
552 * after fsm.h, which is not correct. */
553 #define __FSM_EVENT_ENUM enum fsm_common_events
556 * Value of current event in state functions.
559 #define FSM_EVENT ((__FSM_EVENT_ENUM)(fsm->events[fsm->ev_head].id))
562 * Value of the pointer sent together with the event.
565 #define FSM_EVENT_PTR (fsm->events[fsm->ev_head].data)
568 * Value of the integer data sent together with the event.
571 #define FSM_EVENT_INT ((long int)(fsm->events[fsm->ev_head].data))
574 * Sets current state to @c next. The state is not changed
575 * immediately. The rest of current state function finishes its
576 * execution and then, if @c next is not the current state, the
577 * current state function is called again with ::EV_EXIT
578 * event. Finally a call to the @c next state function (even if it is
579 * the same as current) is executed with ::EV_ENTRY as event.
581 * @param next Next state.
585 #define FSM_TRANSITION(next) \
587 if (fsm->events[fsm->ev_head].id != EV_EXIT) { \
588 fsm_event e = {EV_ENTRY, NULL}; \
589 fsm->last_state = fsm->state; \
590 fsm->last_state_name = fsm->state_name; \
591 fsm->state = &__fsm_func_name(__FSM_NAME, next,); \
592 fsm->events[fsm->ev_head] = e; \
597 #define FSM_TRANSITION(next) error_FSM_XXX_not_defined
601 * Invoke state transition to sub-FSM. The behaviour is almost the
602 * same as of FSM_TRANSITION(), but whenever the sub-FSM returns (see
603 * ::SUBFSM_RET), the current state function is executed with
604 * ::EV_RETURN as event. Moreover, the current state function is not
605 * called with ::EV_EXIT before the transtition.
607 * @param substate Initial state of sub-FSM.
608 * @param data Data passed to the sub-FSM.
612 #define SUBFSM_TRANSITION(substate, data) \
614 if (fsm->events[fsm->ev_head].id != EV_EXIT) { \
615 fsm_event e = {EV_ENTRY, data}; \
616 *(fsm->fnc_sp++) = fsm->state; \
617 fsm->last_state = fsm->state; \
618 fsm->last_state_name = fsm->state_name; \
619 fsm->state = &__fsm_func_name(__FSM_NAME, substate,); \
620 fsm->events[fsm->ev_head] = e; \
625 #define SUBFSM_TRANSITION(substate, data) error_FSM_XXX_not_defined
628 * Return from sub-FSM. ::EV_EXIT is executed for the current state
629 * and ::EV_RETURN for the state where it is returning.
631 * @param data Data returned back to the caller
634 #define SUBFSM_RET(data) \
636 if (fsm->events[fsm->ev_head].id != EV_EXIT) { \
637 fsm_event e = {EV_RETURN, data}; \
638 fsm->last_state = fsm->state; \
639 fsm->last_state_name = fsm->state_name; \
640 fsm->state = *(--fsm->fnc_sp); \
641 fsm->events[fsm->ev_head] = e; \
646 #endif /* __robofsm__ */