Table of Contents

Features for High-Availability and Safety Systems

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:

Undefined State Error Handler

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; 
}

Validate State Transitions

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.

Generate State/Event Definitions with Hamming Distance

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.