|
|
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 .signals text file,
2. define states of your machine in .states text file,
3. create a header file for this type of state machine (this header will be included in .c files where the state machine will be used)
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.
This source file should contain definition of initialization function (created by generator - preprocessing macro) and other items (please refer to code below for details).
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.
DioneOS system contains predefined macros that simplifies state machine definition. It provides useful and easy way for description of the state machine:
1. it requires entering the minimum of information,
2. only specific parts are entered, e.g. signal and states names,
3. standard naming style for state machine items are generated automatically,
4. the information is entered only once - eliminating possible error (e.g. list of states and handlers case),
5. structure of state machine is clear,
Example of state machine definition and usage
Let's assume that the state machine will be named my_sm1
[1] my_sm1.signals - state machine signals definition
DEF_SIGNAL( a ) DEF_SIGNAL( b ) DEF_SIGNAL( c )
[2] my_sm1.states - state machine states definition
DEF_STATE( 1 ) DEF_STATE( 2 ) DEF_STATE( 3 )
[3] my_sm1.h
#ifndef __MY_SM1_H__ #define __MY_SM1_H__ #define SM_PREFIX( x ) my_sm1_##x // this will be used as prefix, this must be first, before system.h include #include "sm_macros_enums.h" BEGIN_DEF_SIGNALS #include "my_sm1.signals" // will be expanded to signals enum END_DEF_SIGNALS BEGIN_DEF_STATES #include "my_sm1.states" // will be expanded to states enum END_DEF_STATES // Function for initialization of state machine SM_INIT_DECL; // is expanded to my_sm1_init(struct os_state_machine_s *sm, int queue_size, void * xdata); #endif
my_sm1.c
#include "my_sm1.h" // do not include system.h or state_machine.h before that #include "sm_macros_handlers.h" // Define handlers first HANDLER( 1 ) //handler for state 1 // this is expanded to: // int my_sm1_handler_state_1( os_state_machine_t * sm, os_event_t * event ); { switch( event->signal ){ case SIGNAL( a )://when signal a appears: return STATE( 2 ); //transition to state 2 case SIGNAL( b ): return 0; //do not change the state default: return 0; } } HANDLER( 2 ) { switch( event->signal ){ case SIGNAL( a ): return STATE( 1 ); case SIGNAL( b ): return STATE( 3 ); default: return 0; } } HANDLER( 3 ) { switch( event->signal ){ case SIGNAL( a ): return STATE( 1 ); case SIGNAL( b ): return STATE( 2 ); default: return 0; } } // here will be handlers list, this must be after handlers BEGIN_DEF #include "my_sm1.states" END_DEF // Initialization of state machine, must be at the end of file, this function is generated and will setup all fields SM_INIT_DEF( STATE(1) )
When you want to use the state machine you need:
#include "system.h" #include "my_sm1.h" struct os_state_machine_s my_sm1_aa; //define state machine descriptor ... os_sm_manager_init( 2, 256 ); //initialize state machine manager (only once) my_sm1_init( &my_sm1_aa, 10, (void*)xdata ); //initialize state machine, each instantion; xdata - some extra data os_sm_manager_sm_activate( &my_sm1_aa ); ... //send event when it is required by: os_event_t ev; ev.signal = SIGNAL( my_sm1, a ); os_sm_manager_send_event( &my_sm1_aa, ev ); or from ISR os_sm_manager_send_event_intr( &my_sm1_aa, 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 |