FW Profile - C1 Implementation
State Machine Implementation

The C1 Implementation represents a state machine through a state machine descriptor (SMD).

A SMD is a data structure which holds all the information required to describe a state machine. Users do not normally manipulate the PRD directly. Instead, they manipulate the pointer to the PRD which is defined as an instance of type FwSmDesc_t. Its internal structure is described in FwSmPrivate.h. Most applications are not concerned with the internal structure of an SMD and can ignore this header file.

Applications manipulate a state machine by passing its SMD to the functions defined by the C1 Implementation. Thus, for instance, an application executes a state machine through the following function call: FwSmExecute(smDesc). Here, smDesc is the SMD of the state machine to be executed.

State Machine Modules

The implementation of the state machine concept consists of several modules as described in the table:

Module Description Files
Core Provides an interface to start and stop a state machine and to send a transition command to it. FwSmCore.h, FwSmCore.c
DCreate Provides an interface to create a new SMD. The functions in this module are simple to use but rely on dynamic memory allocation. Applications which wish to avoid dynamic memory allocation can use the alternative SCreate module. FwSmDCreate.h, FwSmDCreate.c
SCreate Provides macros to instantiate a new SMD (without using dynamic memory allocation) and functions to initialize it. This module is alternative to the DCreate module. FwSmSCreate.h, FwSmSCreate.c
Config Provides an interface to configure a newly created SMD by defining its states and transitions. FwSmConfig.h, FwSmConfig.c
Aux Provides an interface to auxiliary services which are useful during the application development phase. FwSmAux.h, FwSmAux.c

The Aux module is not intended for inclusion in the final application. The DCreate and SCreate modules are normally alternative to each other (but deployment of both in the same application is possible). Applications which are severely constrained in memory can instantiate and configure the SMDs of their state machines by directly manipulating their internal fields. This requires a detailed understanding of the internal structure of the SMD but allows an application to dispense with both the DCreate/SCreate modules and with the Config module. An example of direct instantiation and configuration of an SMD is provided in FwSmMakeTestSM5Dir.

State Machine Actions and Guards

The state machine actions and guards are defined as function pointers of type, respectively, FwSmAction_t and FwSmGuard_t. Applications must provide functions of these two types to implement the actions and guards of their state machines. Both the guard and the action functions are called with the SMD as an argument.

Note that, if a state machine uses the same action or the same guard more than once, the associated function pointer is only stored once in the SMD.

State Machine Data

The SMD includes a field holding a pointer to the state machine data. The state machine data are data which are manipulated by the state machine actions and guards. The exact type of the state machine data is defined by applications for each state machine. In most cases, it will take the form a struct whose fields represents the inputs and outputs for the state machine actions and guards. The SMD treats the pointer to the state machine data as a pointer to void. Functions FwSmSetData and FwSmGetData allow this pointer to be set in, and be retrieved from an SMD.

Error Checking

The state machine functions perform a limited amount of error checking. If they find an error, this is reported through the error code which stores the identifier of the last error encountered by the implementation. The value of the error code can be read with the FwSmGetErrCode function. Nominally, the error code should be equal to smSuccess. If this is not the case, the behaviour of the state machine is undefined.

Thread Safety

The functions defined by the C1 Implementation do not use any global data. They operate exclusively on the data passed to them as arguments. They are therefore inherently thread-safe.

Basic Usage

The basic usage of a state machine instance within an application is as follows:

  1. The state machine descriptor is created. This is most conveniently done using the FwSmDCreate.h module but may also be done using the FwSmSCreate.h module (if it is desired to avoid use of dynamic memory allocation).
  2. The data upon which the state machine operates is loaded into the state machine by means of function FwSmSetData.
  3. The state machine is configured by means of the add* functions in the FwSmConfig.h module which allow an application to define the states and the transitions of the state machine.
  4. The configuration of the state machine may be checked through function FwSmCheck and it may be printed with function FwSmPrintConfig.
  5. The state machine is started with function FwSmStart.
  6. Transitions are commanded to the state machine with functions FwSmExecute and FwSmMakeTrans.
  7. The state machine is stopped with function FwSmStop.
  8. If the state machine descriptor was created using the FwSmDCreate.h module, the memory allocated to the state machine may be released with functions FwSmRelease or FwSmReleaseRec.

Examples of creation and configuration of state machines can be found in file FwSmMakeTest.c. Examples of operation of a state machine can be found in file FwSmTestCases.c or in the Demo Application.

State Machine Extension

The C1 Implementation supports an extension mechanism for state machines which is similar to the inheritance-based extension mechanism of object-oriented languages.

A state machine (the base state machine) can be extended to create a new state machine (the derived state machine). A derived state machine can either be created dynamically with the FwSmCreateDer function or else it can be instantiated statically with macro FW_SM_INST_DER and initialized with function FwSmInitDer.

After being created, a derived state machine is a clone of its base. It can then be configured by: overriding its actions (through function FwSmOverrideAction), overriding its guards (through function FwSmOverrideGuard), or embedding new state machines in its states (through function FwSmEmbed).

The internal structure of the SMD is designed to minimize the memory requirements of derived state machines. An SMD is split into two parts: the Base Descriptor and the Extension Descriptor (see FwSmPrivate.h module). The Base Descriptor holds the information about the state machine topology (its states, choice pseudo-states and their connections) whereas the Extension Descriptor holds the information about the state machine actions and guards and its embedded state machines. During the extension process, only the Extension Descriptor is duplicated whereas the Base Descriptor is shared between a state machine and its children. This significantly reduces memory occupation in a situation where a large number of state machines are derived from the same base state machine. The internal structure of a state machine descriptor is shown in the figure.

SMDExtension.png
P&P Software GmbH, Copyright 2011, All Rights Reserved