|
|
State Machine. More...
Functions | |
os_result_t | os_sm_process_event (os_state_machine_t *sm) |
Process an event if there is any in state machine queue. | |
os_result_t | os_sm_flush (os_state_machine_t *sm) |
Removes all pending events from the queue. |
State Machine.
The DioneOS system defines a template for coding state machines - a set of programming rules that standardize translation from abstract state machine diagram to the C programming language. These measures help to write state machines in clear and well structured form. The part of the DioneOS system that supports state machines consists of an infrastructure for common items and mechanisms for the state machines (i.e. event passing and storage, transitions, etc.). The state machine interacts with other parts of the code by events (os_event_t) which are sent to the state machine. Due to different context and processing time between sender and state machine, it is equiped with its own queue. In the queue incomming events are serialized regarding to the reception time and wait for processing. Because the state machine itself is passive, it must be supervised by active object - state machine manager. This active object has its own thread and is responsible for scheduling of the events processing. All events are processed in the context of that thread. |
1. table of handlers - a functions containing code that process events in each state, 2. queue implemented as ring buffer for pending event storage, 3. optional additional data attached during state machine creation. It also has internal variable that represent current state of the state machine. The state machine should be controlled by sending events, but not directly to state machine, events should be sent via the state machine manager (i.e. os_sm_manager_send_event() function). |
In order to define your own state machine, you need (refer to listings below):
1. specify your signals (types of events) in app_specific/include/sm_signals_user.h
2. define states of your machine (e.g. in my_state_machine.h)
3. provide initialization of the state machine structure, including ring buffer creation as the event queue
4. write a code of handlers, separated for each state. The handler (os_sm_handler_t()) is a function that will be called when event must be processed by the state machine. This function contains switch-case for splitting execution for different types of events (signals). Value returned from the handler determines if the transition to other state occurs. If zero is returned the state machine remains in current state.
The state machine should be initialized and activated. Activation adds it to the state machine manager list and enables events flow from the queue to the handlers.
Example of state machine definition and usage
[1] app_specific/include/sm_signals_user.h
#ifndef USER_SM_SIGNALS_H_ #define USER_SM_SIGNALS_H_ it is included into #sm_types.h , in signal enumeration type. // example of user signals: sig_a, sig_b, #endif //USER_SM_SIGNALS_H_
[2] my_state_machine.h
#ifndef MY_STATE_MACHINE_H_ #define MY_STATE_MACHINE_H_ // Enumerated type for definition of states of the machine typedef enum my_sm1_states{ reserved=0, my_sm1_state1, my_sm1_state2, my_sm1_state3, my_sm1_state_nb //used for determination number of states } my_sm1_states_t; // Function for initialization of state machine os_result_t my_sm1_init( struct os_state_machine_s *sm, int queue_size, void * xdata_a, int initial_state ); #endif //MY_STATE_MACHINE_H_
my_state_machine.c
#include "sm_types.h" #include "sm_manager.h" #include "ring_buffer_ev.h" #include "my_state_machine.h" #include "stdio.h" #include "stdlib.h" //handlers - forward declaration int my_sm1_handler1( os_state_machine_t * sm, os_event_t * event ); int my_sm1_handler2( os_state_machine_t * sm, os_event_t * event ); int my_sm1_handler3( os_state_machine_t * sm, os_event_t * event ); //table of handlers, will be attached to the state machine descriptor os_sm_handler_t my_sm1_handlers[] = { my_sm1_handler1, my_sm1_handler2, my_sm1_handler3}; //number of handlers must be consistent with number of states //initialization of state machine [3] os_result_t my_sm1_init( struct os_state_machine_s *sm, int queue_size, void * xdata_a, int initial_state ) { os_result_t res; sm->handlers = my_sm1_handlers; sm->state = initial_state; sm->states_nb = my_sm1_state_nb; res = os_ringbuf_create_ev( &sm->ev_queue, queue_size ); if( res != OS_STATUS_OK ) return res; sm->xdata = xdata_a; os_sm_manager_sm_activate( sm ); return OS_STATUS_OK; } // the handlers that process events in each state [4]. In this simple example actions performed in the states are // only printing a text, in a real state machine it can be any other code. int my_sm1_handler1( os_state_machine_t * sm, os_event_t * event ) { printf("[%s]", sm->xdata ); switch( event->signal ){ case sig_a: printf("state 1: sig_a --> state2\n"); return my_sm1_state2; case sig_b: printf("state 1: sig_b\n"); return 0; default: printf("state 1: sig_?\n"); return 0; } } int my_sm1_handler2( os_state_machine_t * sm, os_event_t * event ) { printf("[%s]", sm->xdata ); switch( event->signal ){ case sig_a: printf("state 2: sig_a --> state1\n"); return my_sm1_state1; case sig_b: printf("state 2: sig_b --> state3\n"); return my_sm1_state3; default: printf("state 2: sig_?\n"); return 0; } } int my_sm1_handler3( os_state_machine_t * sm, os_event_t * event ) { printf("[%s]", sm->xdata ); switch( event->signal ){ case sig_a: printf("state 3: sig_a --> state1\n"); return my_sm1_state1; case sig_b: printf("state 3: sig_b --> state2\n"); return my_sm1_state2; default: printf("state 3: sig_?\n"); return 0; } }
When you want to use the state machine you need:
#include "sm_manager.h" #include "sm_types.h" #include "my_state_machine.h" struct os_state_machine_s my_sm1; //define state machine descriptor ... os_sm_manager_init( 2, 256 ); //initialize state machine manager (only once) my_sm1_init( &my_sm1, 10, "some_extra_data 1", my_sm1_state1 ); //initialize state machine, each instantion ... //send event when it is required by: os_event_t ev; ev.signal = sig_a; os_sm_manager_send_event( &my_sm1, ev );
os_result_t os_sm_flush | ( | os_state_machine_t * | sm | ) |
Removes all pending events from the queue.
[in] | sm | state machine |
os_result_t os_sm_process_event | ( | os_state_machine_t * | sm | ) |
Process an event if there is any in state machine queue.
[in] | sm | state machine |