p.
itemis CREATE for Eclipse is our most advanced version, offering additional features that are currently exclusive to the Eclipse platform. This version is designed for users who need advanced capabilities beyond the standard web version.
Whether you’re looking for enhanced testing features, deeper integration with C/C++, or support for multi-state machines,
itemis CREATE for Eclipse provides everything you need to take your development to the next level.
If your project requires complex testing scenarios or you are working with embedded systems that rely on C/C++ integration, this is the ideal version for you.
The following features are currently only available in our Eclipse-based version:
You can download itemis CREATE for Eclipse here.
In order to start working with itemis CREATE, you have to install the software on your computer. The installation process is pretty simple, just download the archive, unpack it, and start the executable.
In case you want to install itemis CREATE into an existing Eclipse instance, read section Installing to an existing Eclipse instance.
Installing itemis CREATE on a Windows machine boils down to the following steps:
Congratulations, you have just installed and started itemis CREATE!
You can proceed now by installing a itemis CREATE license or by creating your first itemis CREATE project.
Installing itemis CREATE on macOS boils down to the following steps:
Congratulations, you have just installed and started itemis CREATE!
You can proceed now by installing a itemis CREATE license or by creating your first itemis CREATE project.
Installing itemis CREATE on a Linux machine boils down to the following steps:
Congratulations, you have just installed and started itemis CREATE!
You can proceed now by installing a itemis CREATE license or by creating your first itemis CREATE project.
This chapter outlines the steps to install itemis CREATE on an existing Eclipse instance. Ensure Eclipse is up and running before adding itemis CREATE as an additional plugin.
Please note: On macOS, this only works if your .app file is located in your Applications folder.
Attention!
In the the Help menu, select Install New Software
The Install wizard opens. Click on the Add... button in the upper-right corner.
In the dialog that appears, enter the name and URL of the update repository. You can find the repository URL on the itemis CREATE download page.
Eclipse connects to the repository and displays available software. Select the items you wish to install and click Next >..
If there are any issues with compatibility, Eclipse will attempt to resolve them automatically. Choose the best solution and click Next >..
Review the items to be installed and click Next.
Select the radio button labelled I accept the terms of the license agreements then click Finish.
Eclipse will download and install the software. Once finished, it will prompt you to restart Eclipse. Choose to restart immediately or later.
After restarting, Eclipse will show the Welcome window, now featuring itemis CREATE.
Attention!
To check whether a new itemis CREATE release is available and to install it, select the Help → Check for Updates menu item.
If Eclipse finds any software items to be updated – not just itemis CREATE –, it will guide you through the process of updating them. Generally Eclipse has to be restarted afterwards to have any changes take effect.
You can configure Eclipse as follows to automatically check for updates:
Select the Window → Preferences menu item. The Preferences dialog opens.
Go to the Install/Update → Automatic Updates section. Here you can configure whether and when Eclipse should check for updates and what to do when it finds any.
itemis CREATE come with an evaluation license that is valid for 30 days. If you want to continue working with itemis CREATE beyond that period of time you have to acquire a license .
We offer free of charge academic licenses hich include the complete itemis CREATE feature set. If you think you meet the requirements for these licenses, you can apply for them on our website .
The license manager documentation describes how you can install a license file or configure a license server for floating licenses. To access that documentation, select Help → Help Contents from itemis CREATE’s main menu, then open the itemis CREATE License Management documentation.
This section explains how you can edit statecharts using itemis CREATE.
Statecharts are comprised in
statechart model files. The filename extension of these files is
.sct. Their internal format is
XML Metadata Interchange or
XMI, which is an XML language.
In order to create a new statechart, use the project explorer view:
In order to copy an existing statechart file, proceed as follows:
In order to delete a statechart file, proceed as follows:
itemis CREATE comes with a statechart editor. This section explains the statechart editor and how you can use it to graphically edit your statecharts.
SC Modeling is an Eclipse perspective supporting the modeling of statecharts. The perspective defines the following views and their positions:
You can change the positions and sizes of these views, you can delete them, or add more views, using standard Eclipse mechanisms.
The canvas is the statechart editor’s drawing area. When you create a new statechart model, the canvas comprises the definition section and a single region.
The following list gives an overview of what kind of actions you can perform on the canvas:
[Del] key, or
[Ctrl] and turn the mouse wheel to zoom in or out.
The editor palette provides you with a set of various actions and statechart editing tools. By default, the palette is located right of the canvas, but you can also drag it to the left.
You can hide the palette by clicking on the small triangle on the right-hand side in the palette’s title bar. Click on the triangle again to make the palette reappear.
Editor palette
Below its title bar, the palette contains a toolbar with the following editing action tools (from left to right):
| Symbol | Action | Description |
|
Select | Left-click at an object to select it. |
|
Zoom in | Left-click to zoom in. Press
[Shift] and left-click to zoom out. Drag to zoom to selection.
|
|
Zoom out | Left-click to zoom out. Press
[Shift] and left-click to zoom in.
|
|
Note | Create a note, a text or a note attachment. |
The palette comprises a couple of tools serving to add statechart elements to the diagram (from top to bottom):
| Symbol | Description |
|
Adds a transition. |
|
Adds a state. |
|
Adds a composite state. |
|
Adds an orthogonal state. |
|
Adds a region. |
|
Adds an entry point. |
|
Adds a shallow history state. |
|
Adds a deep history state. |
|
Adds a final state. |
|
Adds an exit point. |
|
Adds a choice. |
|
Adds a synchronization. |
The Outline view allows you to keep the big picture of your statechart model and navigate it easily. It displays the model outline either as a graphical overview or as a hierarchical outline.
Click on the Overview icon in the Outline view’s title bar to engage the graphical overview.
While the statechart editor window – due to zooming or the size of the whole statechart – might display a cutout only, the Outline view shows the whole diagram as an overview. It is scaled down as needed to completely fit into the available area.
A light-grey overlay rectangle represents the statechart editor’s viewport.
Click on the Outline icon in the Outline view’s title bar to engage the hierarchical outline.
The problems view by default lists all errors, warnings and other types of messages in all open projects.
The messages are grouped by message type, typically “error” or “warning”. Click on the show/hide symbol to open or close the respective message group’s contents.
Double-clicking on an entry in the problems view takes you directly to the resource or model element causing the problem.
You can configure the problems view in a multitude of ways, e.g., to group entries by different criteria, to sort them in a specific way, or to restrict them to certain projects. You can even define multiple problems views, each with different selection or display criteria.
To start configuring the problems view, click on the small triangle pointing downwards in the Problem view’s title bar. A drop-down menu will open and display the options that you have.
To configure the view click the small triangle pointing downwards in the view’s title bar. A drop-down menu opens and shows the options you have.
Please note: The problems view reflects the error/warning status of persisted statecharts only, i.e., statecharts that have been saved to the statechart file. If you create an error during editing, for example a new state that is not (yet) connected to any other state, the respective element will have an error marker on the canvas, however, it will not appear in the problems view, unless you have saved the statechart. The same holds true for resolved errors: An error will disappear from the problems view only after you saved the fixed error to the statechart file.
Generally, there are two different ways to edit states and other nodes:
There are certain properties that you can only edit with one of these methods. For example, to modify a state’s position or size, you have to use the statechart editor. To change a state’s transitions' priorities, you have to use the properties view.
Generally, there are two different ways to edit transitions:
There are certain properties that you can only edit with one of these methods. For example, to add guidance points to a transition’s arrow, you have to use the statechart editor. To change a transition’s arrow’s color, you have to use the properties view.
You can attach documentation to states and transitions. In this context, documentation is some text offering additional information to a human reader. In the model, it does not serve any functional purpose.
By default, a state’s rectangle shows the state’s behaviour, and a transition shows its expression alongside its arrow. You can instead display an objects’s documentation, i.e., the documentation of a state or transition:
In order to return back to the object’s normal view, select Toggle documentation again.
While the documentation is shown, you can modify it in the statechart editor. Double-click on the documentation text field to start editing it. Click outside the state or transition to quit editing.
The properties view of states and transition always shows both documentation and statechart language elements side by side in different compartments. This might be a more comfortable way of editing any of them.
In a statechart model, you can have
Their graphical representation differ somewhat, thus editing them is also somewhat different.
You can place a top-level region anywhere on the canvas, and you can change its size at will. To change the location or the size of a region, use the graphical editor. Drag the region to move it elsewhere. Use a selected region’s handles to resize it.
Regions inside an orthogonal or composite state are confined by their enclosing state. They are sized automatically, depending on their contents, and they are arranged either vertically or horizontally.
You can toggle between vertical and horizontally representation of regions in an orthogonal state as follows:
You can change the name of a region in the statechart editor as well as in the properties view.
[Return] key to finish editing.
Statecharts can get rather big and complex. Composite states are a way to reduce complexity and thus make statecharts easier to create, comprehend and maintain. A composite state comprises a state machine of its own within a region. The states belonging to such a nested state machine are called substates. Orthogonal states are a generalization of composite states, comprising two or more independent state machines in separate regions that are executed virtually concurrently.
A complementary way to mitigate the size of large statecharts are subdiagrams. A subdiagram externalizes the possibly large region(s) contained by a composite state into a subdiagram. In this case the composite state no longer displays its substates. Instead it is visualized very similarly to a regular state. The only difference is a small icon in its lower right corner, marking it as a composite state and giving access to its internal structure: the subdiagram. This way a composite state consumes much less space and gives the user the opportunity to better envision the overall picture. Section "Using subdiagrams" explains how to work with subdiagrams, how to create them and how to inline them again, if needed.
Composite states resp. subdiagrams can be nested to any depth.
The statechart editor provides various refactorings to support editing these hierarchies.
As a statechart grows, it may easily become too big to still give a comprehensive overview of the whole model. Subdiagrams come as a solution. Basically, you can “fold away” a composite state into a subdiagram.
Composite state
When the Extract Subdiagram refactoring is executed on a composite state, all containing regions are extracted into a separate diagram. The composite state no longer clutters the diagram with all its internal details, but instead appears almost like a normal state. The only difference is a small decorator icon in the lower-right corner of the state, indicating the existence of a subdiagram. When you hover over this decorator with the mouse cursor, you’ll see a small preview of the subdiagram’s content.
Extracting a subdiagram creates entry and exit points in the subdiagram as needed.
Subdiagram pop-up window
A click on the decorator opens the subdiagram in a separate editor tab. The breadcrumb at the top allows easy navigation throughout the hierachy levels.
Subdiagram editor
Using the inlining subdiagram refactoring, you can turn a subdiagram back into the composite state.
By default, a statechart’s definition section is positioned at the left-hand side of the canvas.
You can edit the definition section in two different modes: Legacy mode and the new pinnable mode. Starting with version 3.3 of itemis CREATE the pinnable mode is the default editing mode.
Legacy mode is the definition section’s traditional editing mode, which has been available in itemis CREATE for a long time already.
To edit the definition section, double-click into it and enter your statements. While editing, syntax highlighting is applied to the text in the definition section. To quit editing, click outside the definition section. Now the text will appear without any syntax coloring.
Technically, the definition section is part of the canvas. If you print the canvas or save it to an image file, the definition section is included in the result. Definition section and top-level region are always scrolled in sync, which might have the rather unwanted effect that your statechart diagram is scrolled off your screen if you have a very long definition section and you are editing something down below in it.
Pinnable mode is an improved editing mode that has been introduced with itemis CREATE 3.20. However, it is slightly incompatible with previous versions, so you have the choice to use it or not.
In pinnable mode, the definition section can be either part of the
canvas (“inlined”) or not (“pinned”), and you can change that at will. The definition section comes with a little pin symbol
at its top-left. Click on it, and the definition section will be detached from the canvas. This has a couple of advantages:
Collapsing the pinned definition section
Expanding the pinned definition section
By default, the pinned definition section takes 20 percent of the canvas' view, but you can resize it as you like.
You can unpin the definition section and inline it with the canvas. To do so, click on the pin symbol
, which in the pinned state is in the definition section’s upper-right corner.
Please note: The definition section is available for top-level diagrams only. If you are editing a subdiagram you will need to use the Properties View to edit the definition of your statechart model.
Please also note: Pinning and inlining the definition section changes your statechart model. You have to save it in order to maintain the current status.
Pinning the statechart diagram definition section
Inlining the statechart diagram definition section
In the pinned definition section, you can edit the name of the statechart by changing the displayed text in the top-center of the section.
Changing the statechart name
Refactoring means modifying certain model aspects while maintaining the model’s semantics. The statechart editor allows for the refactoring of variables, events, interfaces, and states, including composite and orthogonal states. A state’s context menu contains the Refactor submenu with the individual refactoring actions explained below. Depending on certain conditions, a refactoring might be executable or not, which will be explained below.
Using the Rename refactoring, you can change the name of a variable, event or interface throughout your statechart model. Each occurrence of that name will be changed to the new name.
To initiate renaming, right-click on the name of a variable, event or interface in the diagram editor, in the definition section, or in a text field in the properties view, then select Rename ….
Renaming a variable
When building a statechart model step by step, you may come into a situation where you have defined several transitions having the same target state and sharing a common set of actions.
The Fold Incoming Actions refactoring moves these actions from the transitions to the target state’s entry block. To preserve model semantics, only actions that are defined on all incoming transitions will be moved. Since the execution order must be preserved, the refactoring algorithm starts with the right-most action and proceeds action by action to the left. As soon as it detects an action that is not defined on all incoming transitions, it stops moving actions to the entry block.
Consider the following model:
Moving incoming actions to entry block
Only the most-right action y += 42 can be moved to the entry block of the target state. Although x += 1 is also a common action of both transitions, it cannot be moved to the target state, because the semantics of the B → Target transition would change, in that y = x would be executed before x had been incremented.
Another aspect to take into account are transitions leading to target states that are nested in composite states. Consider the following example:
Moving incoming actions into a nested state’s entry block
The actions y = x of the two incoming transitions leading to the Target state cannot be moved to Target's entry block, because doing so would change the model’s semantics. The reason is the composite state’s entry action x += 1. It will be executed after the action of transition A → Target and before the actions in the entry block of Target. Moving y = x from the transition to Target's entry block would change that order. The statechart editor pays regard to this constraint and prohibits the refactoring.
To fold incoming actions, right-click on the state to refactor, then select Refactor → Fold Incoming Actions in the context menu. The menu entry is active only if there are actual actions to move into the target state’s entry block, with the above rules applied.
The fold outgoing actions refactoring is similar to folding incoming actions, except that it moves actions from outgoing transitions to the source state’s exit block. To preserve model semantics, only actions that are defined on all outgoing transitions will be moved. Since the execution order must be preserved, the refactoring algorithm starts with the left-most action and proceeds action by action to the right. As soon as it detects an action that is not defined on all outgoing transitions, it stops moving actions to the exit block.
Preconditions for this refactoring are analog to "Folding incoming actions". Consider the following example:
Moving outgoing actions to exit block
Here, the actions y = x cannot be moved from the outgoing transitions to the exit block of the source state, because the composite state has an exit action. For the Source → A transition, the proper execution order is to first execute x += 1 of the nesting composite state’s exit block, followed by y = x of the transition. Moving y = x to the exit block of state Source would reverse this order and thus will be prohibited by the statechart editor.
To fold outgoing actions, right-click on the state to refactor, then select Refactor → Fold Outgoing Actions in the context menu. The menu entry is active only if there are actual actions to move into the source state’s exit block, with the above rules applied.
This refactoring is the reverse of folding incoming actions. It removes all entry actions from a target state and appends them to each of its incoming transition’s actions.
Transitions crossing the borders of composite states enclosing the target state might inhibit refactoring, see section "Unfolding exit actions" for an analogous example.
To unfold entry actions, right-click on the state to refactor, then select Refactor → Unfold Entry Actions in the context menu. The menu entry is active only if there are actual actions in the state’s entry block that can be moved to the state’s incoming transitions while maintaining semantic equivalence and preserving execution order.
This refactoring is the reverse of folding outgoing actions. It moves all exit actions from a source state and prepends them to each of its outgoing transition’s actions.
Transitions crossing the borders of composite states enclosing the source state might inhibit refactoring. Consider the following example:
Unfolding exit actions to outgoing transitions
Unfolding the exit action y = x of the Source state to the two outgoing transitions would be invalid, because the execution order of said action and the composite state’s exit action would be reversed.
To unfold exit actions, right-click on the state to refactor, then select Refactor → Unfold Exit Actions in the context menu. The menu entry is active only if there are actual actions in the state’s exit block that can be moved to the state’s outgoing transitions, while maintaining semantic equivalence and preserving execution order.
This refactoring creates a new composite state containing the selected states. The latter must belong to the same region.
To execute this refactoring, select one or more states from the same region, right-click on one of them, and select Refactor → Group States Into Composite in the context menu. The menu entry is active only if the selected states belong to the same region.
This refactoring extracts the regions of the selected composite or orthogonal state into a subdiagram. Entry and exit points are created as needed in the subdiagram. See section "Using subdiagrams" for more details.
To extract a subdiagram, right-click on the composite or orthogonal state to refactor, then select Refactor → Extract Subdiagram in the context menu.
This refactoring inlines the selected node’s subdiagram in order to show it directly in the composite state’s diagram region. See section "Using subdiagrams" for more details.
To inline a subdiagram, right-click on a composite state with a subdiagram, then select Refactor → Inline Subdiagram in the context menu.
Proposals assist you when writing statechart language expressions. Whenever editing some text anywhere in the graphical statechart editor or in the properties view, at any point you can press the
[Ctrl+Space] key combination to get some context-sensitive help.
Certain proposals, like statechart language keywords, have documentation associated with them. When such a proposal is selected, either using the mouse or the keyboard, this information is shown in a secondary pop-up window next to the proposal.
You can either use the mouse or the keyboard to select and insert a proposal in the text:
[Return] to actually insert the proposal at the current position.
When a state is selected,
[Ctrl+Space] opens a pop-up window showing a context-sensitive menu with possible action choices to perform on the state.
These action proposals have additional information associated to them. When a proposal is selected either using the mouse or the keyboard, this information is shown in a secondary pop-up window next to the proposal.
You can either use the mouse or the keyboard to execute a proposal:
[Return] to actually execute it.
itemis CREATE support you in quickly finding model elements and navigating to them.
The larger the model, the greater the need to quickly search for certain elements, e.g., for all states with a given name or name pattern, all occurrences of a certain variable, etc. itemis CREATE' searching functionality helps you master even large statecharts.
One option, and the most complex one, is to use the search dialog. You can open it using the
[Ctrl+H] shortcut or by selecting
Search → Search… in the main menu.
Doing so will open a dialog with several tabs, as shown in the following screenshot:
The tab you want to use is Statechart search.
Please note: If you cannot find this tab, you probably disabled it in the past by mistake. You can enable it again by clicking on the Customize… button and selecting Statechart Search, as shown by the following figure:
![]()
Switching to Statechart search will show you a clean and easy to understand dialog, which can be extended using the Show advanced settings check box for a more professional usage. The following subsection describes the possible settings.
User tip: Checking the Remember last used page option in the Customize dialog will help you to keep the focus on the Statechart Search tab for further search processes.
The Statechart search dialog has several options to control your search.
The following table lists the various search options and explains what the search function does if the corresponding checkmark is set.
| Setting | Description |
|---|---|
| Case sensitive | Differentiate between upper-case and lower-case letters in the search string. If this option is not checked, upper-case letters and their corresponding lower-case letters are regarded the same. |
| Regular expression | Interpret the search string as a regular expression. Please note that itemis CREATE supports Java regular expressions, as explained in the java.util.regex.Pattern class API documentation. |
| Search for states/regions | Include states and regions with matching names in the search result. |
| Search for declarations | Include matching declarations in the search result. Declarations are statechart language elements in the definition section, such as variables, events, operations, and named interfaces. The search function will find all occurrences of matching elements. |
| Search for properties | Include elements with matching
properties in the search result. The following items are regarded as properties:
|
| Scope: workspace | Perform the search operation on all statecharts in the workspace. |
| Scope: selected resources | If a statechart editor has the focus, perform the search operation only on that statechart. If the Project explorer view has the focus, perform the search operation on all statecharts in the selected resources. |
After setting the search options as needed, run the search using the Search button. The search results will be shown in a view called Search.
We will demonstrate the search view using the light switch example from our five-minutes tutorial, using the following settings:
| Setting | Value |
|---|---|
| Search string | O* |
| Case sensitive | ✘ |
| Regular expression | ✘ |
| Search for states/regions | ✔ |
| Search for declarations | ✔ |
| Search for properties | ✔ |
| Scope: Workspace | ✔ |
| Scope: Selected resource | ✘ |
The search view consists of three main components and looks like the following screenshot.
| Component | Functions |
|---|---|
Searchbar text section
|
Displays the search string and the number of matches. The latter is updated while the search is running. |
Toolbar section
|
See section "Toolbar section" |
Result section
|
See section "Result section" |
The toolbar section consists of ten buttons with the following functionalities:
| Button | Action | Functionality |
|---|---|---|
|
|
Redo search | Executes the same search again on the possibly changed model. |
|
|
Cancel searching | Cancels a currently running search. The button is active only if a search run is being executed. |
|
|
History | Use this function to display the search history, to select a formerly-executed search (click on Redo search to actually execute it), or to clear the history. |
|
|
Pin search | Pins the results view. Future search results will be shown in a new search view, instead of rewriting the pinned search view. |
|
|
Collapse all | Collapses the search result tree and displays the root entries only. |
|
|
Expand all | Expands the search result tree and displays all search result entries. |
|
|
Search menu | Contains various search options. |
|
|
Minimize | Minimizes the search view and all its sibling views. A “restore” symbol is shown in a sidebar. |
|
|
Maximize | Maximizes the search view and all its sibling views to the full window size. |
|
|
Restore | Undoes the Maximize function. This button is shown only if the search view is maximized. |
The result section displays the matching statechart elements in a two-column, tree-based view.
You can perform certain actions on the entries in the first column:
| Action | Function | |
|---|---|---|
|
Click on the
|
“closes” the node and collapses all child nodes. |
|
Click on the
|
“Opens” the node and expands its immediate child nodes. |
|
Double-click on a matching element | Navigates to the matching element in the statechart editor, as long a it is not a descendant of an internal or interface element. |
| Double-click on a non-matching path element | Closes an expanded node, opens a collapsed node. |
Another realized search feature is to find references of model elements. You can perform this search on choosing Find references in the context menu of:
This will search for usages of the same element in the local statechart and display them in the search view. Using this method can help you to save time searching for usages of variables, events and operations inside your statechart.
The next section introduces the differences between the first method and this method.
As stated in the previous section, Find references is searching for the usages of the exact same model element as selected, whereas in the Search dialog, you have to enter a search string which will find all occurrences of model elements that match the search string.
Finding occurrences of model elements matching the search string makes it possible to search in different statecharts at the same time, while finding references of a model element is limited to the statechart defining that model element. Depending on your search goals, one method could be more suitable than the other.
To clarify the difference between these methods, different search operations were done using the same model. The used model can be taken from the following figure. It does not have any meaning and is only used for clarification purposes.
| Search operation | Results |
|---|---|
| Find references on variable test in the default (unnamed) interface | Finds two matches:
|
| Find references on variable test in named interface first | Finds one match:
|
| Find references on state test | Finds one match:
|
| Search Dialog with the same settings as in section "Search view" and "test" being the search string | Finds four matches:
|
| Search Dialog with the same settings as in section "Search view" and "test" being the search string | Finds one match:
|
| Search Dialog with almost the same settings as in section "Search view", but with Search for declarations deactivated and with "test" being the search string | Finds match:
|
| Search Dialog with almost the same settings as in section "Search view", but with Search for states/regions deactivated and with "test" being the search string | Finds three matches:
|
As can be seen in this case the search dialog has problems with searching references for the variable test in the unnamed interface.
Open model element is another kind of search method. It can be used to quickly navigate to states and regions. To access
Open model element, use the
[Ctrl+Shift+Q] shortcut or select
Navigate → Open model element in the main menu.
By doing so, the dialog shown in the next screenshot will open.
The dialog consists of a single input element
and two output elements
/
.
A search operation performed with Open model element is equivalent to "Searching via search dialog" with the following setting:
| Setting | Value |
|---|---|
| Search string | same as in
|
| Case sensitive | ✘ |
| Regular expression | ✘ |
| Search for States/Regions | ✔ |
| Search for Declarations | ✘ |
| Search for Properties | ✘ |
| Scope: Workspace | ✘ |
| Scope: Selected resource | ✔ |
Differences between
Open model element and
Search dialog are subtle, but noticeable. The results will promptly appear in
while typing your search string in
. The hierarchy of a selected result is displayed in
as a text instead of using a tree.
Navigating to a result can be done by double-clicking on the result. Or select the result and clicking on the
OK button or hit the
[Enter] key.
The Open model element dialog remembers any matching search results. On reopening the dialog, remembered model elements matching the new search string will be displayed above any newly-found elements. This makes it easier to navigate to them again at a later time.
Remembered elements can be removed from the history by selecting them and pressing the
[Del] key or by right-clicking on a remembered element and choosing
Remove from history in the context menu.
The statechart editor allows for comparing two or even three statecharts to each other, displaying the results, and possibly merging selected differences. Figure "Comparing two statecharts" shows a sample comparison result.
Comparing two statecharts
Whenever a statechart is saved to its statechart file, the previous version of the file is saved to the local history.
Warning: The local history typically contains a few recent versions of a file. However, you should never rely on anything being available in the local history at all. It is definitely no replacement for a data backup or a version control system
To compare a statechart to an older version in the local history, proceed as follows:
To compare two statecharts, proceed as follows:
To compare three statecharts, proceed as follows:
A complete statechart or parts of it can be saved as an image file as shown in the following steps:
| Image format | Description |
|---|---|
| BMP, PNG | Lossless pixel image formats |
| JPG, JPEG | Lossy pixel image format. You can specify the image quality via the Quality (%) setting. |
| SVG | Scalable Vector Graphics |
| Portable Document Format |
Note
The image export functionality is subject to the capabilities of your Java Runtime Environment (JRE). You can export images only in those image formats your JRE actually supports.
While you are busily developing a statechart, it is quite common that you have ideas about what else you could or should do to improve the statechart. However, in order to not get side-tracked, you decide to do it later. Examples are to write a proper documentation for a state, to refine a transition whose final specification you don’t have yet, etc.
For all these and other purposes you can define
tasks in all places in your statechart where a comment is allowed. A task is a special comment comprising the words
FIXME or
TODO. Adding one of these words to a comment is called “tagging” the comment as a task.
The nice thing is that you don’t have to remember all the places you took a note and defined a task. itemis CREATE lists all of your tasks in the tasks view. Figure "Tasks defined by tags in the statechart showing up in the tasks view" is showing an example with various tasks being defined in a transition, in a state’s behavior, in a state’s documentation, and in the statecharts definition section.
Tasks defined by tags in the statechart showing up in the tasks view
In the example, state B has been selected in the statechart editor (top), so that the tasks defined in the state’s behavior and in its documentation are shown in the properties view (middle).
Task have a priority. While
TODO stamps a task as being of normal priority,
FIXME indicates a high-priority task.
By default, tasks are ordered by priority in the tasks view (bottom), and high-priority tasks are accentuated by a red exclamation mark. However, you can change the sorting order and other settings using the view’s menu. Click on the little triangle on the right-hand side of the task view’s title to open the view menu.
Double-clicking on a task in the tasks view navigates to the location where the task is defined. If needed, the corresponding statechart diagram is opened. The graphical element holding the task definition is highlighted.
Note
The tasks view is updated only when the statechart is saved.
The example wizard gives you convenient access to the examples in the public itemis CREATE examples repository. You can browse the available examples and read their documentation in the wizard. By a simple click you can instantiate an example as a new Eclipse project. Within such a sample project, you can explore and modify the state machine models using the statechart editor, run the state machines in the simulator, generate source code, etc.
Upon its first invocation, the example wizard downloads the complete examples repository and creates a copy on your local disk. After that, all examples are immediately available to you, even if you are offline. The example wizard will take notice when new examples are available in the online repository and offers to download them. It is also possible to download the examples repository out-of-band and later tell the example wizard where it can find the local copy.
When you start the example wizard for the first time, it does not yet have any examples available that it could show to you. Thus downloading the online examples repository is required as a special first step.
Example wizard when invoked for the first time
When the download is completed, you can browse the examples repository.
You can change the location used by the example wizard to store the online repository’s local clone.
You can change the storage location of your local examples repository clone at any time. In fact, it doesn’t even need to be a clone of the official examples repository. Any directory containing subdirectories with itemis CREATE examples suffices.
The example wizard shows the available examples on the left-hand side.
Click on an example to select it and show its documentation on the right-hand side.
Click on Finish to create the selected example as a new project in your workspace.
Example wizard showing all available examples
The example wizard tries to download a copy of the itemis CREATE examples repository and install it on your local machine. However, if your Internet access is restricted or you don’t have Internet access at all, this will fail.
To circumvent this problem, you can
Subsequently we will explain the necessary steps in detail.
Downloading the repository as a ZIP archive:
Alternatively, you can clone the repository. Cloning the examples repository containing the itemis CREATE examples is more complex than just downloading a ZIP archive. However, you will get certain advantages in return, like the ability to detect and receive updates, the option to create your own examples and submit them as a pull request, or to get hold of the complete history of the examples repository – which could also be considered a drawback, taking its size into account.
git clone 'https://github.com/Yakindu/examples.git'
cd examples
git checkout releaseWhen the example wizard is started and the storage location is a clone of the online examples directory, it checks whether there are any updates in the online examples repository. If new examples are available or existing examples have changed in the online repository, the example wizard offers to update your local examples repository clone accordingly.
Example wizard offering to update the examples repository
If your storage location is a plain directory and not a clone of the online examples repository, no update will ever be done.
If you have a project that you want to share with the community, you can contribute it as an example. Once the itemis CREATE team has reviewed and applied your contribution, it will be available for all users of itemis CREATE via the example wizard’s update functionality.
For more information on how to contribute examples, please visit our Wiki page.
Many aspects of itemis CREATE can be configured by preferences. You can find them here:
In the subsequent sections we will quickly walk through the preferences.
Preferences: Diagram appearance
The diagram appearance preferences define
Please keep in mind that these settings will apply to new elements only. Existing regions, states, etc. will remain as they are. However, you can modify the properties of an existing element anytime, using its properties view.
This option is only available on Microsoft Windows. By default, font scaling is deactivated in itemis CREATE. If you are working on different machines with different Windows font scaling, this option can be enabled to have the same font and box sizes on all machines.
By default, itemis CREATE highlights textual statechart language elements in different colors while the corresponding text fragment is being edited.
If the "Enable syntax coloring" option is checked, syntax highlighting is turned on all the time, i.e., also for text that is not being edited.
You can configure the colors to actually use on the following preference pages:
Check or uncheck the "Enable pinning of statechart definition section pinning" option to toggle between pinning and legacy mode of the definition section. Section "Using the definition section" explains what this is all about.
In order to display transition and region priorities in a statechart, set a check mark at the respective preference option. Section "Transition priorities" explains what transition priorities are and shows an example.
While you are editing a statechart, the statechart editor validates your model on each and every modification you make. That’s very helpful, because the editor provides you with instant feedback, so you can see immediately what is right, wrong, or dubious, and you can take corrective action, if needed.
However, on very large and complex statechart models, validation may take a considerable amount of time, causing delays and impeding your editing. Remove the check mark from Enable live validation, and your model will be validated only before it is saved to the statechart file.
Preferences: Example wizard
You can change the example wizard storage location here. This is a local directory where the example wizard stores your local clone of the examples Git repository. The default is the sct4_examples directory in your home directory.
You could also change the location of the Git repository and the branch to use, but you won’t probably want to do that.
Preferences: Expressions
Certain dialogs in the statechart editor allow you to opt for never seeing them again. By clicking on the Clear button on this preference page the hidden dialogs pertaining to the statechart language will be shown again at their respective locations.
Preferences: Expression syntax coloring
This preference page defines foreground color, background color, font, and style for displaying certain syntactical elements in statechart language texts.
Preferences: Expression templates
Templates are sections of textual code that occur frequently enough to make you want to insert them with a few keystrokes only. This function is known as content assist; the sections of code that are inserted are known as templates.
To insert an existing content assist template, type the initial character, then press
[Ctrl+Space]. The templates whose names begin with that character will appear. Double-click on a template to insert it.
On this preference page you can create, edit, and delete statechart language templates.
Preferences: Generator model
By default, code generators automatically generate artifacts defined by generator models in .sgen files. Using this preference setting, you can switch this behavior off or on.
Preferences: Generator model refactoring
Change these preference settings for refactoring in generator models as you see fit.
The "Save all modified resources automatically prior to refactoring" option is somewhat dangerous, because you might have made changes to files that you intentionally do not want to save to disk – or at least not yet. For that reason, this option is turned off by default.
The
"Rename in editor without dialog if possible" pertains to how the renaming operation is performed. By default, if you click on a name and press
[Shift+Alt+R], you can edit the name directly in the source code, and all other occurences of that element are renamed while you are typing. If this is not possible or if this option is not checked, a dialog will ask you for the element’s new name.
Preferences: Generator model syntax coloring
This preference page defines foreground color, background color, font, and style for displaying certain syntactical elements in generator model texts.
Preferences: Generator model templates
Templates are sections of textual code that occur frequently enough to make you want to insert them with a few keystrokes only. This function is known as content assist; the sections of code that are inserted are known as templates.
To insert an existing content assist template, type the initial character, then press
[Ctrl+Space]. The templates whose names begin with that character will appear. Double-click on a template to insert it.
On this preference page you can create, edit, and delete generator model language templates.
Preferences: SCTUnit
Certain dialogs in SCTUnit allow you to opt for never seeing them again. By clicking on the Clear button on this preference page the hidden dialogs pertaining to SCTUnit will be shown again at their respective locations.
Preferences: SCTUnit refactoring
Change these preference settings for refactoring in SCTUnit source files as you see fit.
The "Save all modified resources automatically prior to refactoring" option is somewhat dangerous, because you might have made changes to files that you intentionally do not want to save to disk – or at least not yet. For that reason, this option is turned off by default.
The
"Rename in editor without dialog if possible" pertains to how the renaming operation is performed. By default, if you click on a name and press
[Shift+Alt+R], you can edit the name directly in the source code, and all other occurences of that element are renamed while you are typing. If this is not possible or if this option is not checked, a dialog will ask you for the element’s new name.
Preferences: SCTUnit syntax coloring
This preference page defines foreground color, background color, font, and style for displaying certain syntactical elements in SCTUnit source texts.
Preferences: SCTUnit templates
Templates are sections of textual code that occur frequently enough to make you want to insert them with a few keystrokes only. This function is known as content assist; the sections of code that are inserted are known as templates.
To insert an existing content assist template, type the initial character, then press
[Ctrl+Space]. The templates whose names begin with that character will appear. Double-click on a template to insert it.
On this preference page you can create, edit, and delete SCTUnit language templates.
Preferences: Simulation
Set your color preferences for the statechart simulator on this preference page.
itemis CREATE supports model simulation.
Simulating a statechart model means to execute it, raise events manually, have time-based and other events being triggered automatically, and observe the model’s behavior.
You can run multiple state machines in parallel and even multiple instances of the same state machine.
An introduction to simulation is given in section "Simulating the light switch model".
You have several options to start a statechart simulation.
The most direct way is to start the simulation based on the statechart model file.
Selecting Run As → Statechart Simulation in the context menu
In order to re-run the simulation you have most recently executed, simply
[Ctrl+F11] on the keyboard
or
To be exact, this operation does not necessarily re-run the last
simulation, but rather the last executed
launch. So if, for example, you first run a statechart simulation followed by running a Java program, then upon pressing
[Ctrl+F11] that Java program is executed once again, not the statechart simulation.
Let’s consider a scenario where you want to execute a simulation that you have run before, but not as the most recently executed launch. So you cannot use the procedure described in section "Repeating the last simulation".
However, as long as you haven’t launched too many other programs in between, chances are good to find your simulation in the history.
Try the following:
When a statechart is simulated for the first time, a launch configuration is automatically created. A launch configuration describes the parameters used for a particular launch. In case of a statechart simulation, it describes which statechart is to be simulated and the simulation mode (event-driven or cycle-based). For details on how to create and modify a launch configuration, see section "Configuring a simulation".
To execute an existing launch configuration, proceed as follows:
The SC Simulation perspective provides selected views that are most useful when running a statechart simulation.
When a simulation starts, the perspective usually changes to the SC Simulation perspective. If this doesn’t happen, you can manually engage the SC Simulation perspective as follows:
Alternatively, you can do the following:
By default, the SC Simulation perspective shows the following views:
The SC Simulation perspective also includes the statechart editor. In a running simulation, the statechart editor highlights active states by coloring their backgrounds.
When a transition is taken, the transition arc leading from the source state to the target state flashes briefly in the transition highlighting color. After that, the target state becomes active and changes its background to the state highlighting color. The source state’s background color becomes normal again.
The SC Simulation perspective
The Simulation view is used to manually raise events and to inspect and modify variables of a running simulation. By default, that view is located on the right-hand side of the SC Simulation perspective, see figure "Simulation view" for an example.
The Simulation view groups events and variables by their interfaces. The unnamed interface appears as default in the interface list. Click on the small triangle left from an interface’s name to show or hide that interface’s contents, i.e., events and variables.
The simulation view also displays
time events, provided the statechart uses time constructs like
after or
every. Press or release the
"show time events" button
to toggle between displaying and not displaying time events. You can click on a time event to raise it, i.e., you don’t have to wait for 24 hours to elapse in real time until the
"after 24 * 60 * 60 s" transition fires.
You can have multiple simulation instances running at the same time. They may simulate the same or different statecharts. Use the simulation view’s drop-down menu to switch between simulation instances.
A digital clock right from the drop-down menu displays the virtual time elapsed in the simulation. It pauses while the simulation is suspended.
The Simulation view
Please note:
Depending on your screen resolution and font size settings, you might not be able to spot the Simulation view by its name, because the tab containing it is quite narrow and might not provide enough space for displaying the title. Hover over the tabs to reveal their respective titles in a pop-up window.
Figure "The SC Simulation perspective" is demonstrating this: The user has hovered the mouse pointer over a tab that just displays the first letters of its title. However, a pop-up window right under the pointer shows the tab’s full title “Simulation”.
.
.
.
to execute a single run-to-completion step.
.
.
You can interact with a running simulation by manually raising events and by inspecting and modifying variables. You can do so at any point in time, but in most cases you will do it while the simulation “sits idle” at its active state and waits for an event to trigger a transition.
To raise an event, proceed as follows:
If the simulated statechart’s execution semantic is
EventDriven then the simulation view will contain a global event called
triggerWithoutEvent. Clicking on it will call the statechart’s
triggerWithoutEvent operation and with that it will perform a run-to-completion step without raising any event.
To inspect a variable’s value, proceed as follows:
Watch the displayed values change as the simulation progresses and actions in states or transitions are executed that modify the variables' contents.
To manually modify a variable’s value, proceed as follows:
[Enter]. The new value is assigned to the variable and replaces the former value.
Section "Creating and executing a launch configuration" describes how to start an existing launch configuration.
The present section describes how to create and configure a new launch configuration for a statechart simulation.


New_configuration to something sensible, e.g.,
Light switch.
Please note: Besides the Main tab described above, a statechart simulation launch configuration also has a tab named Common. This tab is a common standard to all types of launch configurations, and it is described in the Eclipse documentation.
In addition to creating new launch configurations, you can also duplicate or delete launch configurations in the Run configurations dialog. Right-click on a launch configuration and select Duplicate or Delete from the context menu.
itemis CREATE includes two simulator features that increase your productivity considerably when debugging statecharts:
Throughout this chapter we will be using the light switch statechart as an example. It models a lamp which can be turned on and off and also supports various brightness values.
If you press the pressLightOn button, the lamp turns on at its lowest brightness value. If you operate pressLightOn repeatedly, each time the lamp becomes brighter until it reaches its maximum brightness. Pressing the pressLightOff button immediately turns off the light completely. The brightness can only be raised as long as it hasn’t yet reached its maximum value of five. After that, the guard condition disallows to raise it any further.
Here’s the light switch example’s statechart followed by its definition section:
The light switch sample statechart
interface:
in event pressLightOn
in event pressLightOff
interface Lamp:
var brightness: integer
Breakpoints allow for automatically suspending the simulation when a certain element of the state machine is activated. Optionally, a halting condition can be specified to better control the behavior of a breakpoint. Breakpoints can be set on transitions or states. If a state or transition with a breakpoint is reached, the simulation pauses, and the current state of variable values can be examined in the simulation view. It is possible to change variable values and to trigger events that will be raised when the simulation run is manually resumed.
Figure "Transition vs. state breakpoints" depicts at which point of execution a breakpoint pauses the simulation.
To make use of breakpoints, the statechart simulation needs to be executed in debug mode. You have already seen how to start a statechart simulation in run mode. For using breakpoints and snapshots, however, the debug mode is needed.
Starting a simulation in debug mode
Setting a breakpoint
States and transitions with a breakpoint are labeled with a
symbol.
Figure "Breakpoints on transition and state" shows an example.
Breakpoints on transition and state
If the simulation runs into a state with a breakpoint, the state’s entry actions, if any, are executed. After that, execution of the state machine is suspended. The state is highlighted by a small green border.
Highlighting a suspended state
If the simulation runs into a transition with a breakpoint, execution of the state machine is suspended. The transition is highlighted by drawing the transition arc in green. The transition’s actions, if any, are executed when the state machine is resumed.
Highlighting a suspended transition
In order to continue from a breakpoint, you have two options:
in the simulation view. The statechart simulation continues until the next breakpoint is hit or the simulation is terminated.
in the simulation view.
The breakpoints view shows a list of all breakpoints. The respective breakpoint name identifies the state or transition in question. See figure "Breakpoints view" for an example.
You can use the breakpoints view for disabling, enabling, and removing breakpoints as well as for defining conditional breakpoints.
The Breakpoints view
A breakpoint is either enabled or disabled.
.
.
Figure "Breakpoints view" shows an enabled and a disabled breakpoint in the statechart editor and in the breakpoints view, respectively.
You can instruct the statechart simulation to
skip all breakpoints by clicking on the
button in the breakpoints view. The button will appear “pressed”, and while it is, the “skip breakpoints” functionality is engaged. That means, the simulation will not suspend at any breakpoint.
This is different from
disabling all breakpoints, in that each breakpoint keeps its state of being enabled or disabled. Once you disengage the skip breakpoints functionality by clicking on the
button again, the simulation will suspend again at enabled breakpoints and will not suspend at disabled breakpoints.
In order to remove
some breakpoints, select these breakpoints in the breakpoints view, then click on the
button. The selected breakpoints will be removed.
To remove
all breakpoints, click on the
button
A conditional breakpoint has an associated condition and suspends the simulation only if
In order to attach a condition to a breakpoint, proceed as follows:
[Ctrl+Space]. The expression you entered into the text field is validated automatically. In the example shown in
figure "Breakpoints view", the transition suspends the simulation only if the variable
brightness has a value of 4.
In the suspended status of a statechart simulation, you can change variable values using the simulation view. When continuing execution – see section Continuing the simulation – you can observe how your state machine behaves with those modified values.
If you click on an event’s name in the simulation view to raise that event in normal simulation, i.e., while execution isn’t suspended, the state machine processes that event and takes the corresponding transition, if any.
However, while the simulation is suspended, you can raise multiple events, without instant execution. Once execution resumes, the state machine’s behavior depends on its execution scheme:
Let’s have a look at an example. Please note that this example uses the cycle-based execution scheme! This is important, because in the the event-driven case the state machine’s behavior would be different.
Let’s consider that you want to press the "light on" and "light off" buttons at the same time and want to observe what happens. Figure "Raising multiple events simultaneously" shows the scenario:
Raising multiple events simultaneously [1]
symbol, meaning the respective event is not raised.
Raising multiple events simultaneously [2]
. Since the simulation remains suspended, the user can raise multiple events.
Both events are raised and will be handled by the state machine during the next run-to-completion step. The latter will be performed as soon as the user clicks on the step-over button
or the resume button
.
Please note: Under the even-driven execution scheme, multiple events are never processed at the same time. Each event triggers a separate RTC.
Please note: While the execution is still suspended, you can “unraise” an already raised event by clicking on the event symbol
a second time. The blue triangle will disappear, and upon continuation of the simulation the event will not be handled.
It is important to understand that in the event-driven execution scheme there is a queue of events, while in the cycle-based scheme there isn’t. If in the latter case multiple events occur simultaneously, they are all present at the same time, and the state machine has to figure out which event should trigger which transition. For example, what should the light switch state machine do, if it is in the LightOn state and both events, pressLightOn and pressLightOff, have been raised simultaneously?
The answer is transition priorities. The state machine always consults the active state’s transitions in a well-defined order, it fires the first matching transition it encounters, and it forgets about the rest. Transition priorities are specified in the corresponding property of the respective state, see figure "Transition priorities". You can change these priorities, and thus the order the transitions are being checked, by selecting a transition and moving it up or down by clicking on the respective button.
The first transition whose condition is fulfilled will be executed. Under the cycle-based execution scheme, all remaining events are quashed. In the light switch example as shown in figure "Transition priorities", the pressLightOff event would “win” and trigger a transition from the LightOn to the LightOff state, while the pressLightOff event would be discarded.
Transition priorities
p.
In order to deploy a code generator and actually generate code, you have to set up a code generator project. This is described in the following subsections.
For configuring the code generation process, itemis CREATE uses a textual generator model called SGen. It can be created either by using the itemis CREATE Statechart generator model wizard or by creating a text file with the filename extension .sgen.
To create a generator model using the wizard, proceed as follows:
Selecting code generator and statecharts
The result is the specified .sgen file. It has the following format:
GeneratorModel for [GeneratorId] {
statechart [StatechartReference] {
feature [Feature] {
[ParameterName] = [ParameterValue]
}
}
}
The [GeneratorId] represents the unique ID of the chosen generator. Currently, itemis CREATE supports the following code generators out of the box:
create::c – Generator ID for the C code generator
create::cpp – Generator ID for the C++ code generator
create::python – Generator ID for the Python code generator
create::java – Generator ID for the Java code generator
create::scxml – Generator ID for the SCXML code generator
create::images – Generator ID for the statechart image generator
A single generator model may contain multiple
statechart … { … } blocks and thus specify the code generation for multiple statecharts. For each statechart, the generator process can be configured with
Features. Each feature has one or more parameters. These parameters can be configured with
ParameterName
=
ParameterValue.
Besides generating code from a statechart model, it is also possible to generate code from a test file written in the SCTUnit language. The SCTUnit code generators translate SCTUnit tests into a unit test framework of the target langauge. The following generators are available:
*
create::sctunit::c– Generator ID for the SCTUnit C code generator
*create::sctunit::cpp– Generator ID for the SCTUnit C++ code generator
*create::sctunit::python– Generator ID for the SCTUnit Python code generator
*create::sctunit::java– Generator ID for the SCTUnit Java code generator
*create::sctunit::scxml::qt– Generator ID for the SCTUnit SCXML Qt code generatorSee also chapter Generating SCTUnit source code for more information.
Provided you have created the generator model, proceed as follows:
The source files the generator produces depend on the generator itself. Each generator makes use of its specific target language and the latter’s features and best practices. For example, the Java generator generates Java interfaces and classes, and the C and C++ generators generate .h header files and .c source files. The location of the generated sources can be changed in the generator model. The respective options are explained in the following section.
The generator model is executed by a so-called Eclipse builder. Thus, the artifacts are generated automatically whenever the statechart is modified, as long as Project → Build Automatically is checked. If you want or need to execute your generator model manually, select Generate Statechart Artifacts from the package explorer's context menu.
State machine code is fully derived from a statechart model, and section Generating state machine code explains how to interactively run a code generator. Since release 2.9.0, itemis CREATE additionally provides a headless code generator infrastructure. This allows for code generation without a user interface which in turn allows to integrate code generation into continuous integration (CI) build environments.
Best practice is to generate code on the fly during a continuous integration build instead of cluttering your version control system with generated artifacts.
The headless code generator can simply be called from a command line and thus can be integrated with different CI tools easily. No matter if you are using Gradle, Maven or make, all you need is a Java runtime on your build machine.
The headless code generator is not capable to generate images yet.
The SCT installation directory contains the file scc (Linux, macOS) resp. scc.bat (Windows): the statechart compiler. Technically, it is a script file launching the SCT executable, passing proper parameters for headless code generation.
Please include the SCT installation directory in your PATH environment variable, so the scc command can be executed anywhere from a command-line shell!
The following Linux example assumes itemis CREATE to be installed in /opt/software/yakindu-sct:
export PATH="/opt/software/yakindu-sct:${PATH}"
Calling
scc with the
-h option prints the the integrated help information. In a command-line shell, enter the following command:
scc -h
The output should be similar to the following:
--------------------------------------------------------------
SCC - itemis CREATE State Chart Compiler ((c) by itemis AG)
Visit http://www.statecharts.org
--------------------------------------------------------------
usage: scc [-d <path>] [-h] [-m <path(s)>] [-v <arg>]
-d,--baseDir <path> Relative or absolute path to the working directory that contains your statechart projects. If
not set, the current directory is used.
-h Shows help content.
-m,--model <path(s)> A list of comma-separated relative or absolute paths to model(s) used during execution. If not
set, the runtime value of baseDir is used.
-v,--variables <arg> A list of comma-separated key/value pairs to override variables in SGen models. Example:
-v key1=value1,key2=value2
For the purpose of this documentation we are assuming the following directory structure. This includes SCT-related files like generator models and statechart models.
Within our sample directory structure the generator model project1/default.sgen contains the following:
GeneratorModel for create::java {
statechart default {
feature Outlet {
targetProject = "project1"
targetFolder = "src-gen"
}
}
}
The most simple way to invoke the code generator on the command line is to generate the code for a single Eclipse project. Using a commend-line shell, change to the project directory you want to generate code. Example:
cd [somepath]/basedir/project1
Then invoke the statechart compiler without any parameters:
scc
Please make sure scc is on your PATH environment variable. Alternatively specify the path to the scc executable in the command.
--------------------------------------------------------
SCC - itemis CREATE State Chart Compiler ((c) by itemis AG)
Visit http://www.statecharts.org
--------------------------------------------------------
1 gen model(s) and 1 statechart(s) loaded.
Generating 'default' to target project 'project1' ...
default done.
Generated (1 of 1) gen model(s).
The statechart compiler will invoke the code generator for all .sgen files contained in the project directory. It will look them up recursively. You’ll find the generated code at the location specified in the .sgen file:
[somepath]/basedir/[sgen.targetProject]/[sgen.targetFolder]
In this case the statechart compiler determines whether a .project file is available in the current directory and will automatically adjust the generation target to be the parent of the actual project directory to ensure the parameters defined in an .sgen file are interpreted correctly.
Within the root folder of your itemis CREATE installation enter one of the following platform-specific commands. The string
[pathToBasedir] must be replaced by the concrete path to the base directory, i.e., the common parent directory of the project directories.
Windows:
scc -d [pathToBasedir] -m project1\default.sgen,project2\default.sct
Linux:
./scc -d [pathToBasedir] -m project1/default.sgen,project2/default.sct
macOS:
cd SCT.app/Contents/Eclipse/
./scc -d [pathToBasedir] -m project1/default.sgen,project2/default.sct
Please see the following sample output as a result of the command:
--------------------------------------------------------
SCC - itemis CREATE State Chart Compiler ((c) by itemis AG)
Visit http://www.statecharts.org
--------------------------------------------------------
1 gen model(s) and 1 statechart(s) loaded.
Generating 'default' to target project 'project1' ...
default done.
Generated (1 of 1) gen model(s).
As you can see the headless code generation has properly executed. The generated code will be placed into a folder depending on the values configured within your generator model file.
For our example this means the generated code can be found in
basedir/project1/src-gen/
All parameters are essentially optional. The reason is that for a directory structure adhering to Eclipse workspace standards like projects within a root folder, or no additional hierarchies, everything can be calculated automatically.
You can specify a base directory using the -d
basedir option. It is used for two major tasks:
Default: If the
-d option is not specified, this is equivalent to
-d ., i.e., the current working directory will be the base directory.
The target folder of generated artifacts will be evaluated as follows:
basedir/sgen.targetProject/sgen.targetFolder
Use the -m models option to select certain models known by the statechart compiler. Usually these will be
.sgen or
.sct files. However, other model files that are supported by particular code generators, can be specified, too, e.g., C header files for itemis CREATE Professional’s Deep C Integration. The
-m option’s value can be absolute or relative, can be a file or a folder and can be a single value or a comma-separated list of values.
basedir/model.
basedir/statechart_model.
Default: If the
-m option is not specified, this is equivalent to -m basedir, i.e., all model files in and beneath
basedir are processed.
Use the -v name1=value1;name2=value2;nameN=valueN option to override properties
name1,
name2,
nameN, specified in the generator models, by the given values
value1,
value2, and
valueN, respectively. See section
"Using properties and expressions in generator models" for details.
If the scc command fails, here are some tips and fixes.
If you encounter this error message on Linux, this means the scc command was neither able to locate a SCT executable binary nor an eclipse executable. This happens if the scc executable, which is really only a launcher, is not in the same directory as the SCT or eclipse executables. In a itemis CREATE stand-alone installation, the executable binary is named SCT. However, its name is eclipse if you have installed itemis CREATE from an update site into an already existing Eclipse installation. The scc launcher tries to find one of SCT or eclipse and launches the correct one.
This error message is usually issued if you have installed itemis CREATE from an update site into an already existing Eclipse installation and you installed the latter using the Eclipse Installer / Oomph.
Fixing this is easy: You have to change a single line in the headless.ini file in the Eclipse installation directory.
At first, open the eclipse.ini file in the same directory and search for the --launcher.library line. Copy the path that is on the next line. The two lines might look like this:
--launcher.library
/home/user/.p2/pool/plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.400.v20160518-1444
You’ll find a similar entry like in the headless.ini as well, probably looking like this:
--launcher.library
plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.400.v20160518-1444
Replace the path in the headless.ini file with the path from eclipse.ini. After saving headless.ini, scc should work.
Upon execution
scc searches for
.project files which are used to properly interpret generation target locations as specified in the
sgen files. These
.project files are hidden files that contain some meta information about your projects in your itemis CREATE workspace. If
scc does not find these files you might have copied your models to another folder and missed to also copy these
files.
This error usually denotes a configuration problem when using scc in combination with the deep C integration feature. For example, if you are referring to imported C elements in your statechart models, and the corresponding header files can no more be resolved on your CI build server, the linker is unable to find the referenced C elements and produces this error message. To overcome this problem, you might want to check if your settings in C/C++ General -> Path and Symbols do not contain any paths that do not exist on your build environment. Also make sure that scc can access these settings which are stored in the .cproject file.
p.
itemis CREATE comes with a Deep C/C++ Integration feature, which allows for using C/C++ types, variables, and operations directly within the statechart model. C/C++ header files located in your workspace are automatically recognized by the tool, and all contained type and operation declarations are made accessible in the statechart editor with all its editing features like code completion and validation. In addition to your custom C/C++ types, the C99 standard primitive types, like int16_t, are also available out of the box.
Making your self-defined C/C++ types, structs, and unions available in your itemis CREATE statecharts saves you a lot of time and hassle that would otherwise be needed to map data from your C-type variables to statechart variables and vice versa.
The following screencast gives an overview of the Deep C/C++ Integration feature:
Another feature that comes with the Deep C/C++ Integration is the @ShortCIdentifiers annotation. It changes the naming scheme used by the code generator and activates more checks in the statechart validation to ensure that no identifiers produced by the code generator are longer than 31 characters.
Please be aware that the Deep C/C++ Integration requires a Professional Edition License.
Deep C/C++ Integration allows you to use constructs declared in C/C++ header files seamlessly in your statecharts. For C, this includes:
#define statement, e.g.,
#define ARRAYSIZE 20
The following C++ features are supported:
C/C++ features that are currently unsupported:
Using Deep C/C++ Integration is pretty straightforward:
The subsequent sections will explain how to use Deep C/C++ Integration in practice, using a sample project. In this example, we will define some geometry types like Point or Triangle in C/C++ header files and demonstrate how to make them available and use them in a statechart model. While this example covers C constructs only, there is no extra effort involved in using C++ features – with one exception: Your project must be a C/C++ or a pure C++ project.
Now we can create a C header file specifying our own C type definitions which we can use in a state machine later. In order to create the file, let’s proceed as follows:
In the created header file we define a struct type named Point, which we will later use in a statechart. A (two-dimensional) point consists of an x and a y coordinate. We choose int16_t to represent a coordinate, i.e., a 16-bit signed integer. The complete header file containing the struct definition looks like this:
/*
* point.h
*
*/
#ifndef POINT_H_
#define POINT_H_
#include <stdint.h>
typedef struct {
int16_t x;
int16_t y;
} Point;
#endif /* POINT_H_ */
Please note: In C it is possible to define structs, unions and enums without a typedef. They can be referenced by using the corresponding qualifying keyword ( struct, union, or enum, respectively). As the statechart language does not support these qualifiers, the usage of struct, union and enumeration types is currently restricted to those defined by a typedef.
Let’s create a statechart model now to make use of the C type Point we have just defined.
.sct.
Variables are defined in the definition section on the left-hand side of the statechart editor. Double-click into the definition section to edit it.
In order to make use of the struct defined above we have to import the point.h header file:
import: "point.h"
With the definitions from point.h at hand, we can declare a variable pointA of the Point type. In the statechart’s definition section, enter the following text:
interface:
var pointA:
On the right-hand side of the colon in the variable declaration, the variable’s type must follow. In order to see which types are available, press
[Ctrl+Space]. The content assist opens and shows the C types available, depending on the headers imported within your statechart, i.e.
Using content assist to display available types
Selecting the Point menu entry completes the variable definition:
A Point variable
A statechart variable with a C type can be used everywhere a “normal” statechart variable can be used.
Let’s consider the above example extended by an additional count variable of the C99 int8_t standard type. Additionally, we introduce an event that will be used as a trigger to switch between states.
import: "point.h"
interface:
var count: int8_t
var pointA: Point
in event tick
The statechart below uses these variables in various places, i.e., in transition actions, in internal actions, and in guard conditions.
Using C-type variables
Variables of primitive types like
var count: int8_t are accessed as expected, e.g.,
count = 0 or
count += 1;
The dot notation is used to access structure elements. For example,
pointA.x = 0; pointA.y = 0 sets
pointA to the origin of the coordinate system.
When parsing a C header file, itemis CREATE are mapping the C data types to an internal type system. You can open a C header file in Eclipse with the Sample Reflective Ecore Model Editor to see how the mapping result looks like.
In case you are interested in the EMF model underlying itemis CREATE’s type system, you can find it in the source code of the itemis CREATE open edition at /org.yakindu.base.types/model/types.ecore.
itemis CREATE gives you direct access to C header files within the statechart model. This saves time during development, especially while integrating your state machine with your C program. In general you can import (include) all C header files residing in the same project as well as those header files that are available on one of the CDT project’s include paths, see Properties → C/C++ General → Paths and Symbols in the context menu of your C project. Valid file extensions for C/C++ header files: “.h”, “.hh”, “hpp”, “hxx” and “.inc”.
To import a C header file, go to the beginning of your statechart’s definition section, enter
import: and hit [Ctrl]+[Space]. The content assist now shows all C header files you can import (besides other syntactical elements that would be valid here). In our example one of the first includes provided by the content assist is
point.h, which is found in
/Geometry/point.h. Other imports shown by the content assist are provided by the various include paths configured in your CDT project. For example, figure
"Selecting a C header to import" shows headers on the basic
cygwin toolchain on a Windows system.
Please note: Contrary to a C compiler, itemis CREATE do not support transitive imports. That is to say, if a header file a.h imports another header file b.h using the
#includedirective, b.h will not be “seen” in itemis CREATE unless you import it explicitly in your statechart’s definition section.
The following picture for example .
Selecting a C header to import
If we had more than a single header file in the project, we would see them all. The content assist shows all header files in a project, including those in subdirectories. A C header’s path is relative to the statechart it is imported into.
Click on the
point.h entry in the menu to complete the
import statement. The result looks like this:
import: "point.h"
interface:
var pointA: Point
The dot notation to access structure members can traverse an arbitrary number of stages. As an example, let’s define a datatype named Triangle. A triangle is defined by three points. Using dot notation in a statechart, you can navigate from a triangle to its individual points and further on to the points' coordinates.
The C header file triangle.h specifies the Triangle type:
#ifndef TRIANGLE_H_
#define TRIANGLE_H_
#include "./point.h"
typedef struct {
Point a, b, c;
} Triangle;
#endif /* TRIANGLE_H_ */
A Triangle consists of the three Points a, b, and c. Let’s define a Triangle t in a statechart’s definition section as follows:
import: "triangle.h"
interface:
var t: Triangle
With this definition we can use expressions like
t.a.x, see the image below. Regardless of where you are currently editing an expression, you can always use the code assist to explore which fields are available at that very point and of which types these fields are. Example:
Content assist in data structure traversal
Pointers are a core feature of the C programming language. itemis CREATE’s Deep C/C++ Integration is making C pointers available to you in your statecharts. In particular, you can
From version 5.1 Create supports the usage of smart pointers. They can be used externally e.g. in a header file or can be declared internally e.g. as the type of a statechart variable. As smart pointers got introduced in C++11 they are only supported with our C++11 code generator. Other C domain code generators will replace smart pointers with raw pointers. With this addition, some generator options got introduced too to enable the customization of which parts of the generated code the user wants to use smart pointers. For more detail on that please see GeneratorOptions feature .
Please be aware of that unique pointers may result in not functioning code out of the box as they require special handling regarding ownership.
Pointer variables are declared in a statechart’s definition section as shown in the following example:
var n: int32_t
var pInt: pointer<int32_t>
var spInt: shared_ptr<int32_t>
var ppInt: pointer<pointer<int32_t> >
var pTriangle: pointer<Triangle>;
The declarations above declare
Please note: When closing the type specification in a pointer declaration with angle brackets, e.g.,
pointer<pointer<int32_t> >, the>characters must be separated from each other by one or more white space characters. Writing, for example,pointer<pointer<int32_t>>would result in an error. This restriction will be fixed in a later release.
In order to actually assign a pointer to a pointer variable, you have to get hold of that pointer. To retrieve the pointer to a variable v, use v's extension function pointer. That is, for a variable v, the expression v.pointer evaluates to a pointer to v. Each variable has the pointer extension function.
From version 5.1 all variables also have the unique_ptr, shared_ptr, weak_ptr extension functions that will function just like the already existing pointer extension, only retrieving the corresponding smart pointer instead of raw pointer type.
Please be aware that unique pointers may result in not functioning code out of the box as they require special handling regarding ownership.
Example: Let’s say the pointer variable pInt (declared in the example above) should point to the variable n. The following assignment accomplishes this:
pInt = n.pointer
Similarly, a pointer to a pointer to a base type can be retrieved as follows:
ppInt = pInt.pointer;
Or even:
ppInt = n.pointer.pointer
In order to deference a pointer, i. e. to retrieve the value of what the pointer is pointing to, use the value extension function, which is available on all pointer-type variables.
Example: Let’s say the pointer variable pInt (declared in the example above) is pointing to some int32_t variable. The value of the variable pInt is pointing to should be assigned to the int32_t variable n. The following assignment accomplishes this:
n = pInt.value;
Similarly, if ppInt points to a pointer pointing to some int32_t variable, the following statement retrieves the latter’s value:
n = ppInt.value.value;
Passing pointer parameters to C functions is straightforward. Let’s say you have a C function to rotate a triangle around a center point by a given angle. The C function is defined like this:
Triangle* rotateTriangle(Triangle* triangle, Point* centerPoint, float angle) { … }
Provided the function is declared in an imported C header file, you can call it directly like this:
pTriangle2 = rotateTriangle(pTriangle, pCenterPoint, 45.0);
Please note: Assigning a pointer to a pointer variable is only possible if the pointer types are the same.
Unlike other variables, arrays are not defined in a statechart’s definition section, but rather on the C side in header files. Importing a C header containing an array definition makes the array available to a statechart.
While itemis CREATE’s Deep C/C++ Integration provides mechanisms for accessing individual elements of an existent array, arrays must be allocated statically or dynamically in C. Initializing the array elements is possible in C as well as in the statechart. However, depending on the concrete application it might generally be easier in C.
From version 5.1 it is also possible to use the array access on pointers that are declared in the statechart itself.
The header file sample_arrays.h defines a couple of sample arrays:
#ifndef SAMPLE_ARRAYS_H_
#define SAMPLE_ARRAYS_H_
#include <stdint.h>
#include "triangle.h"
int32_t coordinates[] = {0, 0, 10, 0, 5, 5};
Triangle manyTriangles[200];
int32_t * pArray[10];
#endif /* SAMPLE_ARRAYS_H_ */
The following arrays are defined:
As mentioned above, importing a header file containing array definitions into the statechart’s definition section is sufficient to make the arrays available in a statechart. Example:
import: sample_arrays
With this import, you can access the arrays in statechart language expressions, for example in a state’s local reactions:
entry /
coordinates[2] = 42
Writing to array elements is as straightforward as you would expect. Examples:
coordinates[0] = coordinates[0] + 1;
pArray[3] = n.pointer;
pArray[4] = coordinates[0].pointer
Passing arrays as parameters to C functions is straightforward. Let’s say you have a C function sort to sort the elements of a one-dimensional int32_t array and return a pointer to the sorted array:
int32_t* sort(int32_t data[], int size) {…}
Please note that in C a function cannot return an array as such, but only a pointer to it. Analogously you cannot pass an array by value as a parameter to a function, i. e. the data bytes the array is consisting of are not copied into the function’s formal parameter. Instead a pointer to the array is passed to the function, or – to be more exact – a pointer to the array’s first element. To express this in the function’s formal parameter type, you can specify the
sort function equivalently to the above definition as follows. The
data parameter is now specified as
int32_t* data instead of
int32_t data[], but the meaning is exactly the same.
int32_t* sort(int32_t* data, int size) {…}
Provided the function is declared in an imported C header file, you can call it directly like this:
sort(coordinates, 6)
Please note: The current itemis CREATE release only supports statically allocated arrays. Arrays dynamically allocated using malloc() or calloc() will be supported in a later version.
Besides specifying structured types, it is also possible to declare enumeration types in a C header. Here’s the header file color.h, which defines the Color enumeration type:
#ifndef COLOR_H_
#define COLOR_H_
typedef enum {
RED, GREEN, BLUE, YELLOW, BLACK, WHITE
} Color;
#endif /* COLOR_H_ */
Now let’s extend the Triangle defined above by a fill color:
#ifndef TRIANGLE_H_
#define TRIANGLE_H_
#include "./point.h"
#include "./color.h"
typedef struct {
Point a, b, c;
Color fillColor;
} Triangle;
#endif /* TRIANGLE_H_ */
Similar to the Triangle type or any other C type, the Color enumeration type can be used in the statechart, e.g., by declaring an additional interface variable:
import: "color.h"
import: "triangle.h"
interface:
var t: Triangle
var c: Color = Color.BLUE
Please note that unlike structured types, enumeration variables can be initialized directly in their definitions within the statechart’s definition section.
In order to see which enumeration values are available, the content assist, triggered by
[Ctrl+Space], is helpful again.
Using content assist to select an enumeration value [1]
Once initialized, the c variable can now be used, e.g., in an assignment to the triangle t's fill color:
t.fillColor = c;
Accordingly, during simulation, the values of enum variables are displayed in the simulation view. It is also possible to modify them manually.
Using content assist to select an enumeration value [2]
A function declared in a C header file becomes available in a statechart. The state machine can call it as an operation.
Let’s say our rectangle.h header file not only defines the data type, but also declares one or more C functions to operate on them. The following line declares a function named area, taking a Rectangle parameter by value and returning an int32_t result.
extern int32_t area(Rectangle r);
For the sake of the example, let’s assume the function calculates the area of the given rectangle. Of course we could also do this with means built into the statechart language. However, in the general case you neither can nor want to do that.
itemis CREATE parses function declarations in header files and makes the functions available in the statechart language. It doesn’t care where those functions are defined – or whether they are defined at all – nor what they do. Questions like these will become relevant later when the state machine is generated as C source code, compiled and linked to the functions' implementations.
For now, once the statechart knows about the
area function’s declaration in the C header file, the function can be used immediately in statechart language operations. A corresponding
operation declaration in the statechart’s definition section is not needed. Example:
Using content assist to enter a C function call
Here’s the complete example with the area calculations done by the area function:
Example calling the “area” function
Please note: State machines calling C functions as operations are debarred from simulation and debugging. The simulator is not yet capable to call C functions.
Classes and structs declared in C++ header files are usable from statecharts as well.
class Point
{
public:
int32_t get_x();
void set_x(int32_t x);
int32_t get_y();
void set_y(int32_t y);
private:
int32_t x;
int32_t y;
};
By importing a header file containing this C++ class definition, one or more variables of the Point type can be defined in the statechart:
import: "Point.h"
interface:
var PointA: Point
var PointB: Point
out event e
As expected, it is possible to access public functions and fields of these variables. For example, x and y can be set and read from within a state’s or a transition’s reactions:
entry / PointA.set_x(42); PointA.set_y(0)
[PointA.get_x() == 42] / raise e
There are some constraints which you must consider:
Reference types can be used without these constraints.
C++ allows to create generic constructs by defining templates. For example, if you want to be able to create Point objects with integer as well as floating point coordinates, you could write:
template<typename T>
class Point
{
public:
T get_x();
void set_x(T x);
T get_y();
void set_y(T y);
private:
T x;
T y;
};
This definition creates a generic type in itemis CREATE. In the definition section, you then supply the concrete type parameter, here int32_t:
import: "Point.h"
interface:
var PointA: Point<int32_t>
var PointB: Point<int32_t>
out event e
Instead of int32_t, double, ComplexNumber, or any other type could have been specified instead.
itemis CREATE verifies the usage. Thus with
int32_t, the function call
PointA.set_x(4.2) would be flagged as an error.
C++ also allows to create template functions, which can, but don’t have to, be a part of a class.
A typical example is a
max(T a, T b) function:
template<typename T>
T max(T a, T b)
{
return (a < b) ? b : a;
}
Template functions do not have to have their type parameter declared. itemis CREATE checks whether the supplied arguments are compatible. Calling
max(4, 3.5) would be fine, and
T would be inferred to be
double, whereas
max(4, true) is invalid, because integer types and boolean types are not compatible.
In C++, things can be organized in namespaces. Namespaces are typically applied to classes.
namespace Geo {
class Point
{
public:
double get_x();
void set_x(double x);
double get_y();
void set_y(double y);
private:
double x;
double y;
};
}
To use the
Point class, one would have to write
Geo::Point in C++. In itemis CREATE, namespaces are reflected as
packages. For each header file you import into your statechart, a package is created, plus an additional package for each namespace.
In the definition section, one would write:
import: "Point.h"
interface:
var PointA: Geo.Point
var PointB: Geo.Point
out event e
Namespaces can be nested, so if namespace
Geo would be contained in namespace
Math,
Point would be addressed as
Math.Geo.Point.
During a statechart simulation full access to the C data structures is possible on all layers. The user can inspect them as well as modify them in the simulation view.
The state machine below exemplifies this. Initially it defines two rectangles a and b with certain widths and heights. The state machine calculates the rectangles' respective area size, stores their sizes in two int32_t variables named area_a and area_b, and compares them. Depending on the result, it proceeds to state A is larger or to A is smaller. Only if both a and b have the same area – not necessarily the same width and height –, the state machine proceeds to its final state.
When one of the states A is larger or A is smaller is active, the rectangles' properties can be changed. Triggering the compare_size event transitions to the Check state which repeats the area size comparison as described above.
The rectangle comparison statechart
The state machine’s definitions are as follows:
import: "rectangle.h"
interface:
var a: Rectangle
var b: Rectangle
var area_a: int16_t
var area_b: int16_t
internal:
event compare_size
The Rectangle datatype is defined in a new header file rectangle.h with the following contents:
#include "./point.h"
typedef struct {
Point lowerLeft;
int16_t width, height;
} Rectangle;
In order to simulate the statechart, right-click on the statechart file in the project explorer and select Run As → Statechart Simulation from the context menu.
The statechart simulation
Inspecting C data structures
The simulation view in the screenshot above is showing the state machine’s variables and their values. Click to open or close the nested data structures. The image below shows in particular
Warning: Simple C variables and fields in C data structure are not initialized. Never try to read a variable or field you haven’t written before, because it might contain arbitrary values.
Even if the Point data structures in the example above look like having been initialized to defined values, they are not. Without going into details, in C, variables are generally not initialized. This also holds for statechart variables from the C integration. If you are reading a variable, make sure you have written to it before. Otherwise you might get surprising and non-deterministic results.
Change a variable’s or field’s value as follows:
[Enter] key to quit editing and to write the new value to the variable or field. Giving the input focus to another window has the same effect.
[Esc] key. The variable’s or field’s value remains unchanged.
Modifying C data values
In the example, click compare_size to trigger the event. The state machine transitions to the Check state, recalculates the areas, and behaves as explained above.
Rectangle areas modified and rechecked
Given a variable definition in a statechart’s definition section, you can lookup the corresponding type definition. The definition section must be in editing mode, i.e., you must have double-clicked into it. Now press the
[Ctrl] key and move the mouse pointer over the type name. The former changes its shape into a hand symbol and the latter changes into a hyperlink:
Looking up a C type
Click on the hyperlink to open the header file containing the respective type declaration.
Showing the C type definition
Code generation, i.e., turning a statechart model into source code of a programming language, is explained in the section Generating state machine code. Therefore we won’t go into the details here, but instead only put some emphasis on code generation specialties of Deep C/C++ Integration.
In the statechart model introduced above, do the following:
itemis CREATE creates the following generator model in the file c.sgen:
GeneratorModel for create::c {
statechart statechart {
feature Outlet {
targetProject = "Geometry"
targetFolder = "src-gen"
libraryTargetFolder = "src"
}
}
}
itemis CREATE creates the target folders src and src-gen and generates the C source representing the statemachine into them.
Particularly interesting are the files Statechart.h and Statechart.c.
Statechart.h first includes the sc_types.h header followed by very same C header files that have been included in the statechart:
#include "sc_types.h"
#include "rectangle.h"
The generated code in Statechart.h then uses the native standard and user-defined C data types. For example, the statechart implementation defines the type StatechartIface as follows:
/*! Type definition of the data structure for the StatechartIface interface scope. */
typedef struct
{
Rectangle a;
Rectangle b;
int32_t area_a;
int32_t area_b;
Point p;
} StatechartIface;
By including Statechart.h all definitions are available in Statechart.c, too. For example, a getter and a setter function for the Rectangle variable a are defined as follows:
Rectangle statechartIface_get_a(const Statechart* handle)
{
return handle->iface.a;
}
void statechartIface_set_a(Statechart* handle, Rectangle value)
{
handle->iface.a = value;
}
The external area function is called in the entry actions section of state Check:
/* Entry action for state 'Check'. */
static void statechart_enact_main_region_Check(Statechart* handle)
{
/* Entry action for state 'Check'. */
handle->iface.area_a = area(handle->iface.a);
handle->iface.area_b = area(handle->iface.b);
}
It is possible to add annotations to a statechart’s specification to alter their or the code generator’s behavior, see Statechart Annotations.
The C/C++ domain offers one more annotation: @ShortCIdentifiers helps you to keep the generated code compliant to rules which require C identifiers not to be longer than 31 characters (or rather, to be uniquely identified by the first 31 characters). To achieve this, instead of aggressively shortening names which are part of a statechart’s API, itemis CREATE gives feedback about the names that will be generated and warns if any user input results in C code that is non-compliant with the 31 character rule. This puts the user in charge of the naming scheme and keeps the resulting C identifiers predictable.
This is mainly done by:
Please note that the generator model’s option statemachinePrefix is ignored when @ShortCIdentifiers is used.
Keep in mind that all public functions and types of the statechart are prefixed with its name, so keeping that one short helps a lot.
See the following example:
State names that are not globally unique produce errors.
The name of some elements in the definition section produces warnings because resulting identifiers in the source code will be longer than 31 characters.
All issues resolved: the states were renamed to be globally unique and some identifiers as well as the statechart’s name were shortened to keep everything short.
The state’s names need to be globally unique because of a change in the naming scheme of the state enum.
Enum without @ShortCIdentifiers:
/*! Enumeration of all states */
typedef enum
{
House_last_state,
House_main_region_Idle,
House_main_region_Automation,
House_main_region_Automation_heater_Manual,
House_main_region_Automation_heater_Auto,
House_main_region_Automation_heater_Auto_modes_Normal,
House_main_region_Automation_heater_Auto_modes_Absence,
House_main_region_Automation_lights_Lights_Off,
House_main_region_Automation_lights_Lights_On,
House_main_region_Automation_pond_Pond_Off,
House_main_region_Automation_pond_Pond_On
} HouseStates;
Enum with @ShortCIdentifiers:
/*! Enumeration of all states */
typedef enum
{
House_last_state,
House_Idle,
House_Automation,
House_Manual,
House_Auto,
House_Normal,
House_Absence,
House_Lights_Off,
House_Lights_On,
House_Pond_Off,
House_Pond_On
} HouseStates;
Notice how the state’s names are not prefixed with their containing regions anymore to save characters.
The name shortening algorithm for the static functions works like this, again without @ShortCIdentifiers:
/* prototypes of all internal functions */
static sc_boolean check_main_region_Idle_tr0_tr0(const House* handle);
static sc_boolean check_main_region_Automation_tr0_tr0(const House* handle);
static sc_boolean check_main_region_Automation_heater_Manual_tr0_tr0(const House* handle);
static sc_boolean check_main_region_Automation_heater_Auto_tr0_tr0(const House* handle);
static sc_boolean check_main_region_Automation_heater_Auto_modes_Normal_lr0_lr0(const House* handle);
static sc_boolean check_main_region_Automation_heater_Auto_modes_Normal_tr0_tr0(const House* handle);
static sc_boolean check_main_region_Automation_heater_Auto_modes_Absence_lr0_lr0(const House* handle);
static sc_boolean check_main_region_Automation_heater_Auto_modes_Absence_tr0_tr0(const House* handle);
static sc_boolean check_main_region_Automation_lights_Lights_Off_tr0_tr0(const House* handle);
static sc_boolean check_main_region_Automation_lights_Lights_On_tr0_tr0(const House* handle);
static sc_boolean check_main_region_Automation_pond_Pond_Off_tr0_tr0(const House* handle);
static sc_boolean check_main_region_Automation_pond_Pond_On_tr0_tr0(const House* handle);
With @ShortCIdentifiers annotation:
/* prototypes of all internal functions */
static sc_boolean Idle_tr0_check(const House* handle);
static sc_boolean Automation_tr0_check(const House* handle);
static sc_boolean Manual_tr0_check(const House* handle);
static sc_boolean Auto_tr0_check(const House* handle);
static sc_boolean Normal_lr0_check(const House* handle);
static sc_boolean Normal_tr0_check(const House* handle);
static sc_boolean Absence_lr0_check(const House* handle);
static sc_boolean Absence_tr0_check(const House* handle);
static sc_boolean Lights_Off_tr0_check(const House* handle);
static sc_boolean Lights_On_tr0_check(const House* handle);
static sc_boolean Pond_Off_tr0_check(const House* handle);
static sc_boolean Pond_On_tr0_check(const House* handle);
Deep C/C++ Integration natively supports the following primitive C types. That is, in a statechart without any additional data type definitions, the following types are readily available:
The current release candidate of itemis CREATE PRO is still missing some C functionalities that will be approached as soon as possible by subsequent releases. Among others, the following issues are known to be not available yet:
There is a known syntax issue when declaring nested pointers in the statechart’s definition section. It is required to put a space
between every closing character (>) after declaring the type for the pointer.
Type range validations are currently not implemented. As a consequence, it is possible to e.g., assign an int32_t value to an int8_t variable one without any warning.
In C it is possible to define structs, unions and enums without a typedef. They can be referenced by using the corresponding qualifying keyword ( struct, union, or enum, respectively). As the statechart language does not support these qualifiers, the usage of struct, union and enumeration types is currently restricted to those defined by a typedef.
Using the C/C++ domain, it is possible to call functions that are declared in header files. The generated code will do this correctly, but the simulation will not actually evaluate the functions, for multiple reasons:
Due to this, we decided not to implement this feature, and doing so is currently not on our roadmap.
However, when using our testing framework SCTUnit, you have the option to mock these functions, and these mocks are then called during testing.
Using the C/C++ domain allows you to import classes defined in a C++ header file, and use them as types. This means that you can instantiate objects of these types just like in regular C++ code. However, itemis CREATE currently does not support constructors, so there are certain limitations:
var o: MyClass. The constructor of the generated statechart class will then automatically call the default constructor of
MyClass to instantiate the object.
var o: pointer<MyClass> - this way, the constructor of the statechart does nothing at all. Instead, you can then assign a proper value to it, ideally
after you call the statechart’s
init-function, and
before you call the
enter-function. This ensures correct initialization before the statechart is running.
Please note that the preceding list of restrictions might not be complete. If you discover any further problems, please do not hesitate to contact us! Your feedback is highly appreciated!
p.
The behavior of large systems is often too complex to be captured by a single statechart. So if a statechart gets too large you should think about splitting it into two or more smaller parts. Beside the fact that the smaller state machines are easier to handle and maintain there are additional reasons for using multiple state machines instead of single monolithic ones:
This chapter describes how you can use itemis CREATE to model and simulate a system which consists of multiple collaborating state machines and how you can embed a statechart as a sub machines into another statechart. This chapter introduces all relevant concepts using an example.
The example is a traffic control of a street crossing using traffic lights. While a single traffic light is not so complex the coordination of different traffic lights on a crossing is a good example to highlight the collaboration between different state machines.
The example consists of a system of three state machine instances. There are two instances of the statechart TrafficLight . Each instance just cares about controlling the different modes of a single traffic light. The TwoWayTrafficControl coordinates both traffic lights and makes sure that the traffic is always safe by making sure that no two traffic lights are green at the same time.
First of all – in order to enable collaboration between separate state machines it must be possible that state machines can reference other state machines. To establish such a reference two steps are required:
import: "xyz.sct" in the statecharts declaration area. Specify relative paths if the statecharts are not located in the same directory.
var otherMachine : SomeMachineType
For our example statechart TwoWayTrafficControl the declarations look like this:
import: "TrafficLight.sct"
interface:
var trafficLightA : TrafficLight
var trafficLightB : TrafficLight
According to the steps described above the statechart TrafficLight.sct is imported. As two instances of this referenced statechart are required, two variables are defined. So if you want to implement a three or four way traffic control you can simply define as many variables for state machine references as you require.
A statechart does not only contain the definition of behavior. It also includes structural properties like its declared variables and events. These define its public interface and this interface is represented by a type.
Lets take a look at the example statecharts to get an idea how the state machine types look like:
The statechart
TrafficLight.sct defines the type
TrafficLight and the statechart
TwoWayTrafficControl.sct defines
TwoWayTrafficControl. The types include all members defined in the statecharts declaration section. The variables which are of type
TrafficLight are references to instances of this type.
You should know the following facts about state machine types:
IStatemachine. This type defines additional life cycle operations which are implemented by each state machine.
<StatechartName>States. It defines an enumeration value for each state of the statechart.
If you know the state machine code which is generated from statecharts then you will discover that the definitions of the state machine types directly match the definitions of the generated code.
State machine types are always used as reference types. This implies that the state machine which defines a variable of a state machine type does not own the state machine instance. It will never be created by the state machine itself.
As a state machine type is a regular type you can use it like any other type. So you can assign state machine references to variables, use it as event payload, pass it as operation parameter, or use it as an operation’s return value.
Variables of state machine references can be reassigned. A valid value is
null.
null is the default value
after initializing a state machine.
A state machine reference can be used to interact with the referenced state machine. All elements which are exposed by the state machine type can be used:
The statechart TwoWayTrafficControl raises different events on the referenced state machines.
Different states (like
Release A) also use outgoing events (
trafficLightA.released) as transition triggers.
A loosely coupled architecture makes use of asynchronous message passing and this perfectly matches to statechart events. A statechart which raises an event should not make any assumptions when the event is processed.
Accessing variables implies a tighter coupling of state machines as these are accessed in a synchronized fashion.
As an example the statechart TwoWayTrafficControl could configure the TrafficLight state machines using variables that these provide.
entry / trafficLightA.config.realeasePeriod = 60
Here the v ariable releasePeriod is set as an entry action. releasePeriod is defined by the named interface config thus it is accessed in two step using the dot expression ‘.’ .
In addition to the events and variables which are declared by the statechart, also additional life cycle operations exist. As explained before (see type
IStatemachine in previous chapter), they implicitly exist for each state machine and can be used to control its life cycle.
| operation | purpose |
| enter() : void | An inactive state machine can be activated by calling this operation. During activation the initial state will be activated and all required entry actions are executed. A state machine is inactive by default after creation. |
| exit() : void | A call to exit deactivates an active state machine. During exit, all active states will be exited and all relevant exit actions will be executed. After exit, no state is active. |
| isActive() : boolean | Returns true if the state machine is active and false otherwise. A state machine is active if there is at least one active state. This operation can be used in guards to test the life cycle state of a state machine. |
| isStateActive(state) : boolean | Can be used in guards to check the activation of a specific state. The state parameter must be of the state machines state enumeration type. |
| isFinal() : boolean | Returns true if all active states are final states. The final state won’t change until the state machine is exited and reentered. This operation can be used in guards to check if a state machine has finished its work. |
| runCycle() : void | Performs a state machine run-to-completion step. If a state machine takes full control of a cycle-based state machine then it has to decide when the run-to-completion step must be executed. |
| triggerWithoutEvent() : void | For EventDriven statecharts, it performs a state machine run-to-completion step without raising any event. It can be also used by the client code. |
Using these operations implies a tighter semantic coupling of separate state machines. It is the basis for the implementation of sub state machines as described in the following chapter.
An example for using life cycle operations is given in:
A common concept for structuring statecharts is the decomposition into different sub state machines. This is a concept that you can find in modeling languages like the UML and others.
The basic idea is that a state machine which is assigned to a state as sub machine is executed as if it is part of the enclosing state machine. This means its life cycle is coupled to the life cycle of its owning state. It will be activated when its parent state becomes active, and will be deactivated when the parent state deactivates.
Such a sub machine pattern can be defined using the life cycle methods introduced in the previous chapter. The pattern for using sub state machines looks like this:
entry / otherMachine.enter
oncycle / otherMachine.runCycle
exit / otherMachine.exit
The call to
runCycle is only required if the referenced state machine is cycle-based. The equivalent is the following statement:
submachine otherMachine
The
submachine statement is not only a shortcut. It is more expressive, less verbose and avoids errors by applying higher level validations. You can simply use this statement like any other within the state. Using it is recommended when you want to use sub state machines.
If the referenced state machine is event-driven, then the
triggerWithoutEvent operation can be called, which will perform a run-to-completion step without raising any event.
This allows the guard conditions to be evaluated and the transitions to potentially fire. It is also suitable for firing transitions with the “always” keyword.
So lets take a look how sub state machines can be applied to the traffic control example. The state Operate contains several sub states which control the traffic flow by alternately releasing and blocking the traffic flow of the two directions.
This set of sub states consists of two groups which are similar to each other. The first group consists of the states all blocked before A, Release A, and A Released. The second group is identical except for the fact that A is replaced by B. So the behavior is cloned. Sub state machines can be used to eliminate such redundancies.
Here, introducing the submachine required three steps.
var trafficLight : TrafficLight
var process : ReleaseProcess
entry / process.trafficLight=trafficLightA
submachine process
[process.isFinal]
This results in the following TwoWayTrafficController and ReleaseProcess state machines:
This example shows a typical scenario where using sub machines makes much sense. Here, sub machine controls a process which consists of several steps. Here, it just contains a happy case but it may also define error states. This process can be reused easily if the state machine should be extended to a 3 or 4-way traffic control. So setting up a 4-way traffic control in the initial statechart would require 4x3=12 states while using a sub machine requires 4+3=7 states.
In this example the state machine
process is used as sub machine in both states
Process A and
Proces B. When state machine
process reaches its final state, the state transition from state
Process A to state
Process B will be executed. During this state transition, first,
Process A will be exited. As a result also the sub machine will be exited. Second,
Process B will be entered. As a result, the
process state machine will be configured to use the other traffic light state machine and the
process state machine will be activated by calling its
enter operation. This will activate the initial state
Safe. So the
process state machine is reset to control the next process.
Sub machines are comparable with sub regions and as it is possible to define multiple sub regions for a state it is also possible to define any number of sub state machines. It is even possible that a state defines both – sub regions and sub machines. If both are defined then they are processed according to the execution order:
Additionally, the order of the
submachine statement within a state’s behavior definition is relevant for the execution order:
submachine statements.
submachine statement are executed before entering the sub machine. Those defined after are executed later. This may be relevant for properly setting up sub machines.
submachine statement are executed before exiting the sub machine. Those defined after are executed later. This may be relevant for properly tearing down sub machines.
submachine statement are executed before executing the sub machine’s run-to-completion step. Those defined after are executed later.
As shown in the example a state machine can be used as a sub machine within different states. The only constraint that must be considered is that these states must be exclusive to each other so that both states can’t be active at the same time. In other words, a machine can only be a sub machine in one active state at once. The subsequent use of a state machine as sub machine is no problem.
The ability to access the state machine life cycle operations which were introduced in the previous chapter provides the basis for the implementation of sub state machine. Nevertheless, the concept of sub state machines defines tight life cycle constraints and this is just one pattern to control a state machine. The life cycle operations can also be used to control state machines beyond the concept of sub machines. So it is possible to enter a machine in a state and exit it in another state.
Future versions of this document will discuss different principles and best practices for multi state machine modeling.
The statechart simulation supports the simulation of multiple statechart instances. Simply choose a statechart and choose Run As > Statechart Simulation from the menu.
If the statechart defines variables which refer to other statechart types then the simulation engine will care about setting up the simulation scenario which includes statechart instances of the involved statechart types.
When starting the simulation for the statechart TwoWayTrafficControl the simulation view will list TwoWayTrafficControl.sct as the current simulation session. Additionally, the statechart instances which were created for the simulation session are listed as children of the simulation session.
The first statechart simply has no specific name and is of type TwoWayTrafficControl . The second and third are instances of the statechart TrafficLight. Their name is the name of the variables which are defined by TwoWayTrafficControl as statechart references.
If you click on the statechart instances then a simulation viewer for the specific statechart instance will be opened.
In the detail view below also the variables that reference statecharts are visualized with a statechart icon. You can unfold the details of the referenced statechart by clicking on the grey triangle.
The simulation engine creates statechart instances according to the following strategy:
As described in the previous chapters - statechart instances never create other statechart instances. Statecharts are created by the simulation environment.
After all statechart instances were created and connected the simulation engine will activate the root statechart instance. All other instances are not activated. This implies that the root statechart must initiate the activation of the referenced machine instances. This can be done by
If this is the case then everything works out of the box. There are additional cases where controlling the referenced statechart’s life cycle is not desired, e.g. to have a system of loosely coupled instances. Such systems typically just send events to each other and are inherently asynchronous. If you run the simulation for one of the involved statecharts then all instances except for the simulation root will never be activated.
In these cases you should setup an additional statechart which controls the life cycles of the loosely coupled state machine instances. This statechart defines the system behavior and thus we call it system statechart.
This case can be illustrated using the traffic light control example. Here, all involved statecharts interact using events. An additional statechart StreetCrossingSystem.sct defines the system behavior. This includes the start up sequence of all involved statechart instances.
The system statechart defines a reference called controller to a TwoWayTrafficControl state machine type. It does not start up everything immediately – what would be possible – but defines a set of states which define different system scenarios. The initial state is Off. In this state no state machine is active. By raising the event startAll the system enters the state On which makes sure that all state machines are active. Mention that the system behavior can access the referenced statecharts of referenced statecharts.
The system behavior also defines an additional state for each TrafficLight state machine instance. Here, a temopary outage of a TrafficLight is simulated by deactivating the machines.
System statecharts can be used to fully control state machines. They can be used to set up complex system scenarios and finally may automate execution sequences to bring the system in a defined state which would require much click work for the user.
SCUnit supports unit testing of multiple state machines. A SCTUnit test is defined for a state machine type which is the test instance of the unit test.
If the statechart defines variables which refer to other statechart types then the test environment will care about setting up the test scenario which includes statechart instances of the involved statechart types. Here the same instantiation strategy as described for the simulation is applied.
If the statechart under test does not control the life cycle of the referenced state machines, then this can simply be done by the test case itself.
An simple test case for the traffic control example could look like this.
testclass TwoWayTrafficControl for statechart TwoWayTrafficControl {
@Test operation testStartUp() {
enter
trafficLightA.^enter
trafficLightB.^enter
assert active (main.Off)
assert trafficLightA.isStateActive(TrafficLightStates.Off)
assert trafficLightB.isStateActive(TrafficLightStates.Off)
}
}
In SCTUnit state machines must be activated explicitly. this is also true for the state machine under test which is a
TwoWayTrafficControl state machine instance. The machine under test is activated by the
enter statement while the two
TrafficLight state machine instances are activated by calling the
enter operation on the reference.
The following assertions check if the initial states were activated. This is done by using the built-in function
active for the machine under test while the referenced machines are tested using the
isStateActive operations.
To be able to call the
triggerWithoutEvent operation for
EventDriven statecharts a variable have to be defined for the statechart with the type of
Statemachine. After that through this variable, every operation defined by the statechart type will be accessible.
Use the SCTUnit built-in functions for the state machine under test and use the operations defined by the state machine types for the referenced state machines.
If a statechart uses other statecharts then this will be the same on the level of the generated code. You will find dependencies from the generated using state machine type to the the generated used state machine type.
The code generation process does not change when statecharts use other statecharts. Simply define the code generator ( sgen ) files as before. Make sure that the generator properties, especially those that relate to output paths fit together.
p.
itemis CREATE comes with an SCXML domain which allows to generate SCXML code from your statechart, as well as to simulate and test it in a way that is compliant to the SCXML execution semantics.
SCXML, short for State Chart XML, is a statechart interchange format. It is based on XML and has been standardized by the W3C. This standardization makes statecharts highly portable and independent of a particular implementation. The prerequisite is of course that the respective execution environment corresponds to the SCXML specification.
The current version of the specification was released by the W3C in September 2015. A “hello world” in SCXML looks like this:
Please be aware that the SCXML Integration requires a Professional Edition License.
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="hello">
<final id="hello">
<onentry>
<log expr="'hello world'" />
</onentry>
</final>
</scxml>
The XML defines all the states, transitions, events and variables used in the state machine. Besides the state machine’s structural elements, the SCXML standard also defines the execution semantics of that state machine. And this is one of the biggest advantages of SCXML – the same statechart model can run on different SCXML engines on different platforms and it always behaves in exactly the same way – as long as the engines conform to the specified execution semantics.
SCXML is supported on nearly all platforms. For Java, Apache Commons SCXML is the most popular SCXML Engine. There are even SCXML engines written in JavaScript to be used in web applications, like SCION. Another very popular platform that uses SCXML for Human Machine Interfaces is the SCXML Interpreter for Qt.
To use the SCXML domain, just select it on the domain selection page when creating a new statechart. Alternatively, you can select it in the statechart’s property view. When using the SCXML domain, everything will by fully compliant with the SCXML standard. We adapted the built-in simulation engine to reflect the SCXML execution semantics, and of course the SCTUnit framework also supports the SCXML standard. Thus, you can be sure that your SCTUnit test results exactly reflect the behavior of the SCXML engine of your choice.
Generating SCXML code works like with any other code generator. You need to create a generator model and select the SCXML code generator. Please note, that your statechart must have the SCXML domain enabled.
In the generator model, you need to specify the target folder for the generated XML file. For this, you can use the Outlet feature like for any other code generator in itemis CREATE:
GeneratorModel for create::scxml {
statechart example {
feature Outlet {
targetProject = "scxml.example"
targetFolder = "gen"
}
}
}
This example will generate the XML file into the “gen” folder of your “scxml.example” project.
You can also omit the targetProject attribute and specify a path on your file system. The path can be absolute or relative to the generator model location.
Statecharts with the SCXML domain can also be simulated in the same way standard statecharts are simulated. The only difference is that the itemis CREATE simulation engine will use the Apache Commons SCXML engine under the hood. This ensures that the simulation shows the same behavior as when using the SCXML model in other contexts. The same holds for using our test framework SCTUnit with an SCXML statechart.
p.
itemis CREATE statechart models are executable. There are many use cases that require information about the execution itself. Examples are remote debugging of state machines, execution analysis, testing, co-simulation and others. This information may be provided live during the execution or it could be used post-mortem when the execution of the system already finished. In any case this information must be explicit and it must be possible to store it persistently and provide other tools access to this information.
The YAKINDU Execution Tracing (YET) infrastructure provides open formats, protocols, and APIs. It enables interoperability between state machines which execute on a target in the one side and itemis CREATE (and other) tools on the other side.
This chapter describes some application scenarios at first and then describes how to use YET
Please be aware that
YET tracing and debugging requires a
Professional Edition License.
Please be aware that
YET tracing and debugging is currently only supported by the
C code generator.
The execution trace model enables interoperability between different tools and as such serves a large number of application scenarios. The possible interoperability is shown in the following figure.
Interoperability based on execution traces
One important part is to enable execution tracing and stimulation for all contexts in which statecharts are executed. One important context is a concrete collaborative embedded system which executes one or more state machines. The others are simulations like the itemis CREATE interpreter based simulation or a Functional Mock-up Interface (FMI) based co-simulation context. On the other side there are tools which analyze the system or the statechart execution. These interpret and analyze the statechart execution traces in a specific way. Some of these just consume execution traces. Others can also stimulate execution and as such can be executed ‘in the loop’ with statecharts.
The execution trace decouples the statechart execution from analysis tools. So, both sides can be combined in a flexible way with each other. There are some application scenarios which are implemented based on this concept.
In (embedded) software development scenarios, CREATE Statecharts are transformed to state machine code that runs within a target application. To enable model-level debugging of these state machine implementations within the itemis CREATE, a YET based integration is applied.
Integration scenarios for model-level target debugging
Model-level debugging may cover two variants. First, a bidirectional online integration based on streams (YET stream). Second, a file-based integration (YET file) which covers offline post-mortem analysis of execution traces.
In both cases YET must contain execution trace events that allow:
YET stream is bidirectional and also supports
on the state machine if that direction is supported by the target application.
Of course YET traces can be analyzed manually as the file format is human readable. This is already a great help in the day to day work. Additionally, tool support enables the visualization of execution traces using the itemis CREATE simulation UI. This enables the playback of traces stored in files or the live visualization and interaction based on a YET stream.
While the model-level target debugging supports the interactive analysis of a state machine execution there are cases where automated checking of execution results are required. This is the case if execution traces are very large or must be analyzed very often. A specific kind of automated execution analysis, which is supported by itemis CREATE, is SCTUnit. SCTUnit is a model-level unit testing framework and can check statechart behavior for correctness. As a YET trace is a representation of a statecharts behavior it can be used as a subject of test. According to the the debugging scenario, which are described in the previous section, unit tests can be executed on a execution trace which is stored in a file. If it is connected to a statechart using a YET stream then also stimulation of the statechart and an ‘in the loop’ execution is possible. This can be used to set up HiL (or other kind of XiL) test scenarios.
Testing state machine execution on an embedded target
SCTUnit itself is a text based language which follows the typical XUnit testing approach. Test cases are implemented as simple scripts. These scripts can directly be executed in the itemis CREATE tool or can be transpiled to code. A very simple example for a statechart unit test provides the following code:
testclass TrafficLightTest for statechart TrafficLightCtrl {
@Test operation switchTrafficLightOn () {
// given the traffic light is inactive
assert !is_active
// when
enter
// then traffic light is off which means no color was switched on
assert TrafficLight.displayRed
assert !TrafficLight.displayGreen
assert !TrafficLight.displayYellow
}
@Test operation switchLightFromRedToGreen () {
// given
switchTrafficLightOn
// when
raise TrafficLight.releaseTraffic
proceed 60s
// then
assert TrafficLight.displayGreen
}
}
The unit test is defined as a test class. A test class refers to the statechart under test and defines two test cases. Each is implemented by a test operation. ‘assert’ statements check properties of the state machine. The ‘enter’ statement activates the state machine and ‘raise’ raises an event. So both are stimuli processed by the statechart. The ‘proceed’ statement controls time and continues the test after 60 seconds have passed. A unit test is optimized to check specific execution sequences. For more complex conditional and iterative scenarios also ‘if’ statements and ‘while’ loops can be defined which can make use of local variables.
Co-simulation is a major field for the application of YET. itemis CREATE can be used to create Functional Mock-up Units (FMUs) that can be integrated in co-simulations based on the Functional Mock-up Interface (FMI) standard. Different scenarios are supported. First, the debugging and testing approaches described in the previous sections can also be applied using a FMI co-simulation instead of a concrete embedded target. An additional scenario is to integrate the CREATE Statechart simulation into a FMI co-simulation using a tool wrapper FMU. This is a FMU which wraps a simulation tool and does not execute a statechart on its own. Instead, the statechart is executed by the CREATE Statechart simulation. This simulation runs in a separate process. This requires execution events to be exchanged between the FMU and the simulator.
FMU tool wrapper delegates execution to itemis CREATE simulator
Integrating CREATE Statecharts in FMI-based co-simulation scenarios requires additional plugins. A detailed description of this features is not included in this document but it will follow soon. Please contact statecharts@itemis.com if you require more information earlier.
In addition to the tool features provided by itemis CREATE, out of the box analysis and trace visualization tools can be integrated. An example for such a tool is impulse which is a visualization and analysis workbench. It enables engineers to understand and debug complex systems by relating signals and data from arbitrary sources to statechart execution. This data can be visualized using a rich set of diagrams.
CREATE Statechart execution visualized in impulse
The correlation of data from different sources and its visualization is not scope of itemis CREATE tools. Thus it makes much sense to integrate dedicated tools for this purpose. impulse can read and analyse YET trace files of CREATE Statecharts.
Analyse execution traces from file
In order to use execution tracing for target debugging or unit testing some implementation and configuration steps are necessary. In general the system which executes the statechart must be prepared to produce an execution trace and the system which analyses a YET trace must be prepared properly. Depending on the system simple configurations or manual implementation tasks are required. Here the following cases are described:
A generated state machine which should be debugged or remote controlled must be enabled for execution tracing. This consists of the following steps.
Preparing the generated state machine for execution tracing.
Set up the trace handling in the target application. This step may require application specific implementation work.
By default the tracing feature of state machines is disabled in order to save resources if it is not required. Nevertheless enabling tracing for a state machine is a simple configuration topic for code generators. The second step is more complex as it may require application specific implementation work.
Enable tracing when generating state machine
The generated state machine code must be instrumented for raising trace events. So you first have to enable the tracing feature in your sgen generator file. This can be done by adding another feature called
"Tracing" to the C generator configuration. The configuration below gives an example.
GeneratorModel for create::c {
statechart tictoc {
feature Outlet {
targetProject = "example"
targetFolder = "sc"
libraryTargetFolder = "sc/base"
}
feature Tracing {
generic = true
}
}
}
The feature
"Tracing" has the property
"generic" with the value
"true" (
"false" is the default). As a result an additional C header file named
"sc_tracing.h" is generated. It declares the generic trace API which will be used by all state machines with enabled tracing. These declarations include the type
sc_trace_handler. A state machine uses such a trace handler instance to call trace callbacks which can be processed by a trace handler implementation. This API is independent of YET. It can be used to adapt any execution tracing or logging infrastructure.
Adding a YET tracer
While the step before enables a generic trace API for the state machine, an additional generator can be configured which generates a YET specific implementation of the
sc_trace_handler. This is also straightforward. Simply add a new
sgen file to the project. Corresponding to the example above it looks like:
GeneratorModel for create::c::yet {
statechart tictoc {
feature Outlet {
targetProject = "example"
targetFolder = "sc"
libraryTargetFolder = "sc/base"
}
}
}
This generator model uses
create::c::yet generator instead of the
create::c. It just requires an
Outlet feature and the same values should be used as in the normal C code generator model. This generator adds several additional source files to the project:
sc_yet.[h|c] - implements a set of functions which are used to create and parse YET execution events. This implementation is completely independent of statechart semantics and can be used to support execution tracing for other models.
yet_sc_tracer.[h|c] - this module implements all generic parts for YET statechart tracing which can be applied to all statecharts. So it is aware of statechart semantics and provides an implementation of
sc_trace_handler.
<Statechart>Tracer.[h|c] - this module implements the statechart model specific parts of a YET tracer.
<Statechart>Meta.[h|c] - this module defines data structures which provide names as strings for the different statechart features like variables, events, and states. This is separated from the tracer module as these structures are independent from YET and can be reused for other purpose (like a generic MQTT adaption).
Please keep in mind:
Setting up tracing in the application
The generated infrastructure is capable of producing and consuming trace. What is missing is connecting this functionality to the outside world. This part is not covered by a code generator and must be implemented manually based on the API which is provided by the generated code and reusable software components.
Connecting trace infrastructure to physical channels
The generated code provides a
yet_sc_tracer instance. This instance must be connected to physical channels which care about the physical handling of trace events. Three different implementations of physical channels are currently provided:
yet_logger - logs trace events by writing them to the standard output stream of the process.
yet_file_writer - writes trace events to a file using a single line for each entry. The result is a valid yet trace file.
yet_udp_stream - implements a bidirectional transport of trace events based on UDP datagrams. Each datagram contains a single trace event.
The integration of the tracer instance on the one side and the physical channels on the other side are based on observable message streams. These support an asynchronous, reactive programming model and allow a loose coupling between the different components. The message streams are based on the principles of reactive extensions (ReactiveX) without making use of any external ReactiveX library.
The
yet_sc_tracer provides an observable stream of trace messages where each trace message is a simple string. This stream can be observed by any number of observers and all physical channels provide an observer which can subscribe to the observable trace messages. In addition, the tracer defines the observer
message_receiver which processes incoming trace events which are stimuli for the state machine. This can, for instance be connected to the observable
received_messages which is provided by the bidirectional
yet_udp_stream. The figure above shows how the observable streams are connected. On the code level the setup is straight forward. First, we need a state machine and initialize it.
SomeStateMachine machine;
someStateMachine_init(&machine);
The code for setting up the timer service is omitted here. Next, a tracer instance is defined and initialized.
yet_sc_tracer tracer;
someStateMachine_init_sc_tracer(&tracer, &machine);
Without a physical channel, tracing has no effect. So we need to define and initialize an instance for each discussed physical channel.
yet_file_writer yet_file;
yet_udp_stream yet_stream;
yet_logger yet_log;
yet_file_writer_init(&yet_file, "machine.yet");
yet_udp_stream_init(&yet_stream, ip, port);
yet_logger_init(&yet_log);
Now all instances are in place but we have to connect the observable streams with the observers as discussed above. This is done by defining a list of observers for each observable which must be connected.
sc_observer* out_trace_observers[] = {
&(yet_log.message_logger),
&(yet_file.message_writer),
&(yet_stream.message_sender) };
sc_observer* in_trace_observers[] = {
&(yet_log.message_logger),
&(tracer.scope.message_receiver) };
Then the observers must subscribe to the observable.
SC_OBSERVABLE_SUBSCRIBE(&(yet_stream.received_messages),
in_trace_observers);
SC_OBSERVABLE_SUBSCRIBE(&(tictocTracer.scope.trace_messages),
out_trace_observers);
The observer subscriptions here go beyond the scenario which is described by the previous figure as the
yet_log will also care about the incoming trace events from the
yet_stream instance. So it logs outgoing and incoming trace events. Some more things should be mentioned here:
This provides a high flexibility for the application developer and the implementation of the existing physical channels is a good template for custom implementations.
Debugging a statechart YET trace is simple. Within a statechart editor or on the model file entry in the project explorer choose "Run As > Statechart Trace Debugging" from the context menu.
Starting a trace debug session
This will launch the trace debugger and by default will try to read the execution trace from the file "trace.yet" from the root of the project folder. If it is not already in place then create this trace file e.g. by starting the application with enabled YET file tracing. The UI of the trace debugger is identical to the regular simulation UI.
If you want to choose a different trace file you have to reconfigure the run configuration which was created by the "Run As > Statechart Trace Debugging" action. To do this choose "Run As > Run Configurations…" from the context menu. The "Run Configurations" dialog pops up and choose the proper entry in the category "Statechart Trace Debugging". The tab "Statechart Trace" provides several configuration options.
First the instance name is used to distinguish between multiple running instances of the same state machine if multiple state machines are executed on the target and if they share a common trace channel. The default is just the name of the statechart model.
The obviously most important option is how you want to read or receive traces. It is possible to choose one of three trace provider:
If UDP or TCP based YET streams are used then the debugging UI supports raising events and modifying statechart variables.
Configuration of trace debug session
After that click “Apply” and “Run”. The trace debugger UI will be activated. If UDP or TCP trace provider are used then no active statechart state may be highlighted in the Debugger UI. This is always the case if no remote target is connected or if the statechart is not yet activated on the remote target.
Instead of the interactive debugger a trace can also be consumed by unit tests. Within a SCTUnit editor or on test file entry in the project explorer choose "Run As > Statechart SCT Unit Trace Test" from the context menu. The unit test runner will start up an execute the tests.
All points regarding setting up a run configuration for trace tests is identical to the steps required for the interactive trace debugging as the same configuration dialogs are applied. The only difference is that the category ‘SCT Unit Trace Test’ is used instead of ‘Statechart Trace Debugging’ .