SinelaboreRT Header Logo

SinelaboreRT

It's better when it's simple!

User Tools

Site Tools


Sidebar

Modelling-Tool specific Intro

Getting started

How-To

Language Backends

Examples

Designers Toolbox

There are better ways to model state machines than using spread sheets!

In the past different μC manufacturers have published application notes about the benefit of using state machines for the design of embedded software. An example is the application note SLAA402 from Texas Instruments (TI). It suggests to generate source code based on a spread sheet table. Nowadays several affordable UML modeling tools are available supporting the efficient design of state machines in a graphical way. SinelaboreRT generates production quality source code from state diagrams created with many different UML tools. Give it a try!

Latest Changes

wiki:backends:cpp_lang

Generating C++ Code

Since version 1.5 sinelabore supports the generation of C++ code. C++ offers many features that should be avoided in embedded systems. Therefore the code generator uses just a very small subset of C++. Actually only classes, public/protected/private member variables and methods are used. Features like virtual functions, templates etc. are not used by default. Since version 4.0 several new configuration parameters were added. With the new parameters there is much more flexibility to adjust the generated code towards own needs. Some of the new parameters require a compiler supporting at least the C++ 2011 standard (i.e. set –std=c++11 for g++ or clang++). To generate C++ code call the code generator with the command line flag ’-l cppx’.

The generated code does not follow the state pattern as you might expect (if you are familiar with common design patterns). The reason is that the machine code is completely generated and no hand-coding is involved.

The code generator supports code generation from models with regions. A region is an orthogonal part of a state. Regions allow to express parallelism within a state. A state can have two or more regions. Region contains states and transitions. To add a region in astah* right click to a state and select Add region from the context menu.

An example state diagram with regions is shown below. Imagine how much effort it would be to manually write the code for this machine. And even worse how difficult it would be to maintain it over time when new states/events are added.

All details about the C++ backend are available in section “Generating C++ Code” of the manual.

Example code:

/* Command line options: -v -p CADIFRA -l cppx -o testcase testcase.cdd   */
/* This file is generated from testcase.cdd - do not edit manually  */
/* Generated on: Thu Feb 13 19:50:07 CET 2020 / version 4.1 */
 
 
#include "testcase.h"
#include "testcase_ext.h"
#include <stdio.h>
 
extern unsigned char msg;
extern unsigned char condition;
 
namespace simulator {
 
  testcase::testcase(void)
  {
    m_initialized=static_cast<int>(0U);
  }
 
 
 
  /* State names */
  const char states[]=
    "S3\0S2\0S21\0S22\0S11\0S1\0S12\0";
 
  const unsigned short state_idx[]={
    0,3,6,10,14,18,21,25};
 
  /* Event names */
  const char events[]=
    "evA\0NO_MSG\0";
 
  const unsigned short evt_idx[]={
    0,4};
 
  const char* testcase::getNameByState(const unsigned short state) const {
    return states+state_idx[state];
  }
 
  const char* testcase::getNameByEvent(const TESTCASE_EVENT_T evt) const {
    return events+evt_idx[evt];
  }
 
 
  // Helper(s) to reset history
  void testcase::resetHistoryS1(void){
    stateVars.stateVarS1=S11;
  }
 
  void testcase::resetHistoryS2(void){
    stateVars.stateVarS2=S21;
  }
 
 
  // Helper(s) to find out if the machine is in a certain state
 
  bool testcase::isInS3(void) const {return(((stateVars.stateVar== S3)) ? (true) : (false));}
  bool testcase::isInS2(void) const {return(((stateVars.stateVar== S2)) ? (true) : (false));}
  bool testcase::isInS21(void) const {return(((stateVars.stateVarS2== S21)&&(stateVars.stateVar== S2)) ? (true) : (false));}
  bool testcase::isInS22(void) const {return(((stateVars.stateVarS2== S22)&&(stateVars.stateVar== S2)) ? (true) : (false));}
  bool testcase::isInS11(void) const {return(((stateVars.stateVarS1== S11)&&(stateVars.stateVar== S1)) ? (true) : (false));}
  bool testcase::isInS1(void) const {return(((stateVars.stateVar== S1)) ? (true) : (false));}
  bool testcase::isInS12(void) const {return(((stateVars.stateVarS1== S12)&&(stateVars.stateVar== S1)) ? (true) : (false));}
 
  // Helper to get id of innermost active state
 
  testcase::States testcase::getInnermostActiveState(void) const {
 
    testcase::States state = NUM_STATES;
 
    if(isInS12()){
      state = S12;
    }else if(isInS11()){
      state = S11;
    }else if(isInS22()){
      state = S22;
    }else if(isInS21()){
      state = S21;
    }else if(isInS3()){
      state = S3;
    }else{
      // intentionally left blank
    }
    return state;
  }
 
  // Initialize method. Must be called once to init the machine
  void testcase::initialize(){
    //call on entry code of default states
    if(m_initialized==static_cast<int>(0U)){
      m_initialized=static_cast<int>(1U);
 
      //Create copy of statevar
      stateVarsCopy = stateVars;
 
      // Set state vars to default states
 
      stateVarsCopy.stateVar = S1; /* set init state of top state */
      stateVarsCopy.stateVarS1 = S11; /* set init state of S1 */
      stateVarsCopy.stateVarS2 = S21; /* set init state of S2 */
 
 
 
    printf("S1 Entry\n");
 
    printf("OnEntryS11\n");
 
 
      // Copy state variables back
      stateVars = stateVarsCopy;
 
    }
 
  }
 
 
  // State machine event handler
  int testcase::processEvent(const TESTCASE_EVENT_T msg){
 
    int evConsumed = 0U;
 
 
 
    if(m_initialized==static_cast<int>(0U)){
      return static_cast<int>(0);
    }
 
    //Create copy of statevar
    stateVarsCopy = stateVars;
 
    /* action code */
    printf("Outer test action\n");
 
 
    switch (stateVars.stateVar) {
 
      case S1:
 
        switch (stateVars.stateVarS1) {
 
          case S11:
            /* action code  */
            printf("Action S11\n");
 
 
            if(msg==evA){
              /* Transition from S11 to S3 */
              evConsumed=1U;
              /* OnExit code of state S11 */
              printf("OnExit S11\n");
 
              /* OnExit code of state S1 */
              printf("S1 Exit\n");
 
              /* Action code for transition  */
              printf("evA\n");
 
              /* OnEntry code of state S3 */
              printf("OnEntryS3\n");
 
              /* adjust state variables  */
              stateVarsCopy.stateVar = S3;
              stateVarsCopy.stateVarS1 = S11;
            }else{
              /* Intentionally left blank */
            } /*end of event selection */
          break; /* end of case S11  */
 
          case S12:
          break; /* end of case S12  */
 
          default:
            /* Intentionally left blank */
          break;
        } /* end switch S1 */
      break; /* end of case S1  */
 
      case S3:
        /* action code  */
        printf("Action S3\n");
 
 
        if(condition==1){
          /* Transition from S3 to S11 */
          evConsumed=16U;
          /* OnExit code of state S3 */
          printf("OnExit S3\n");
 
          /* Action code for transition  */
          printf("condition==1\n");
 
          /* OnEntry code of state S1 */
          printf("S1 Entry\n");
 
          /* OnEntry code of state S11 */
          printf("OnEntryS11\n");
 
          /* adjust state variables  */
          stateVarsCopy.stateVar = S1;
          stateVarsCopy.stateVarS1 = S11;
        }else{
          /* Intentionally left blank */
        } /*end of event selection */
      break; /* end of case S3  */
 
      case S2:
 
        switch (stateVars.stateVarS2) {
 
          case S21:
          break; /* end of case S21  */
 
          case S22:
          break; /* end of case S22  */
 
          default:
            /* Intentionally left blank */
          break;
        } /* end switch S2 */
      break; /* end of case S2  */
 
      default:
        /* Intentionally left blank */
      break;
    } /* end switch stateVar_root */
    // Copy state variables back
    stateVars = stateVarsCopy;
 
    return evConsumed;
  } // end processEvent
 
 
 
 
 
 
 
} //namespace simulator
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
wiki/backends/cpp_lang.txt · Last modified: 2020/02/15 13:06 by pmueller