For high availability applications it is desirable to detect serious errors happening outside the state machine code but effecting the correct execution of the state machine. Such errors might come from a runaway pointer overwriting key variables, power brownout corrupting a bit or a bad ram cell losing a bit to name a few. To detect and handle such situations is an overall system design task. But the code generator can help you to detect inconsistencies of the state machine offering the following two mechanisms:
You can provide error handler code that is executed in the default path of the switch/case statements. This helps to detect undefined values of the state variables. See configuration key UnknownStateHandler
.
Example:
switch (instanceVar−>stateVar) { case S1: ... case S2: ... default: error_handler(); // your error handler break; }
The code generator optionally generates a validate function that checks if a transition from a present state to a new target state is allowed (i.e. modeled in the state diagram). To enable the generation of the validate function set parameter ValidationCall=yes
in the configuration file. This validate function has to be called from a user provided handler that is automatically called from the generated state machine code. This indirection allows you to define the reaction in the case a transition is not allowed. The validation code is automatically generated for you. In a single CPU setup the validation function runs on the same controller that executes the state machine code. But it is also possible to execute the validate function on a second CPU in a redundant CPU setup.
Example state machine:
case S22: if(msg==(TESTCASE EVENT T)ev32){ /∗ Transition from S22 to S21 ∗/ testcaseValidationHandler(S22, S21, instanceVar−>inst id); evConsumed=1U; /∗ OnExit code of state S22 ∗/ ...
Example for an user defined handler:
// your own handler begins here void testcaseValidationHandler(uint16_t from, uint16 t to, uint8_t machineId){ uint8_t testcaseValidate(from, to); // checks if this transitions is allowed if (retCode!=0U){ // transition not allowed reboot(); // or whatever is best in your system }else{ printf ("Transition␣allowed\n"); return; } }
Generated validation code for some example machine:
#define SIZE_TRANSITION_TABLE (31U) #define TRANSITION(from,to) (uint16_t)((from * 127) + to) /* Hash table of valid transitions */ static const uint16_t valid_transitions[] = { 16249U , /* S1->S3 */ 10880U , /* S111->S111 */ 9728U , /* S11->S11 */ 10489U , /* S132->S131 */ 15360U , /* S3->S3 */ 9754U , /* S11->S12 */ 13030U , /* S12->S11 */ 13056U , /* S12->S12 */ 6680U , /* S13->S11 */ 9704U , /* S11->S13 */ 16181U , /* S1->S13 */ 10892U , /* S111->S112 */ 15292U , /* S3->S13 */ 12404U , /* S112->S111 */ 6724U , /* S13->S3 */ 5745U , /* S22->S21 */ 6731U , /* S13->S1 */ 3855U , /* S21->S22 */ 1009U , /* S4->S3 */ 15247U , /* S3->S4 */ 914U , /* S4->FINAL0 */ 1016U , /* S4->S1 */ 896U , /* S4->S4 */ 5461U , /* S2->S1 */ 16159U , /* S1->S21 */ 9694U , /* S11->S2 */ 9682U , /* S11->S21 */ 9779U , /* S11->S1 */ 16205U , /* S1->S11 */ 16256U , /* S1->S1 */ 16171U , /* S1->S2 */ }; uint8_t testcaseValidate(uint16_t from, uint16_t to){ uint16_t hash = TRANSITION(from,to); uint16_t x; for(x = 0U; x < SIZE_TRANSITION_TABLE; x ++) { if(valid_transitions[x] == hash) { return 0U; } } /* return an error */ return 1U; }
The validate code uses some predefined types. Define them in a header that fits your system needs and include it by setting the parameter AdditionalValidateIncludes
in the configuration file.
It is possible to generate the states and events in an ascending order but using a user defined hamming distance between them. So in case one or more bits swap accidentally the state machine will end up in the default path which can then call an error handler. See parameters UseHammingCodesForEvents
, UseHammingCodesForStates
and HammingDistance
.
Example:
UseHammingCodesForEvents=yes
UseHammingCodesForStates=yes
HammingDistance=3
/*Events which can be sent to the state-machine */ typedef enum { evInnerS3=0U, ev3434=7U, ev111=25U, evInnerS111=30U, evBH=42U, evBG=45U, evBF=51U, ... TESTCASE_NO_MSG = 461U } TESTCASE_EVENT_T;
In case of any questions and suggested send us a mail.