Statechart modeling: Simulation and Execution using Yakindu
Original by Marlon Dumas and Luciano García-Bañuelos (StatechartPractice2.pdf)
In this lab session, we will introduce a few advanced features, and in the end, we will use these features to solve an exercise. Above there is a link to our material from previous years, but let's actually learn to come up with the relevant experiments ourselves!
Part 1: Orthogonal Regions and Raising Events
In Yakindu, you have tools for the UML concepts of State, Composite State, Orthogonal State and Region, but the only real concepts are actually state and region. A region is a container for states! You cannot put a state anywhere else except in a region, so there is a top-level region that is called "main region" by default. The UML concepts are then as follows:
UML Name | In terms of states and regions |
---|---|
State | A state with no regions |
Composite State | A state with a single region |
Orthogonal State | A state with a multiple regions |
Why is this important? Well, because you can create a state and add a region to it. The result is exactly the same as using the Composite State tool. Adding another region to it will be the same as having used the Orthogonal State tool. Try creating a composite state. Keep in mind that you need a start state in each region!
You need to know a bit more about interfaces and then the experiments can begin! Interfaces allow communication with outside components. For testing, it's most convenient to use an unnamed interface. We will also experiment with communication inside the chart, so for these we use internal events. We can raise events with the keyword raise
. You can begin using the following interface declarations:
@CycleBased(100) interface: in event go internal: event e event f event g
Try to create a chart in order to answer the following questions. You will first answer this for cycle-based execution and then for event-based execution.
- If two orthogonal regions can react to an event. Which one will react? Is the the first, the second, or both?
- Can there be a chain of events raised or do we only react to a single event in each cycle?
- Does the order of regions matter? Can there be a case where an event is triggered in, say, a second region, but it is ignored because the region that would react to this came before? Is there some way to reorder regions?
- Given a single user input, can we raise internal events such that we take multiple steps within a single region in response to that user event?
When you are done, change the first line to @EventDriven
and repeat the above questions. Note that the difference between execution models applies only to internal events: if you raise input events of an external interface in your chart, these will behave the same in the event-driven mode as in the cycle-based execution. It doesn't usually make much sense for the state chart to raise input events of external components, but I sometimes abuse this possibility in order to simulate outside components within the chart.
Finally, it's worth discussing whether any of these execution models allow an infinite loop of events being raised such that we never respond to anything else. Warning! If you test this, you may have to force quite Yakindu...
You may compare your conclusions with the documentation. I do hope you are eager experiment on your own, but you could avoid genuine learning by just looking at my conclusions:
Here's an example of the sort of chart I used:
We may draw the following conclusions:
- In cycle-based execution, regions are executed until completion in a fixed order (usually, left to right). Each region may take a transition if the corresponding event is enabled when it is the region's turn to run. Raising an event simply enables events for regions down the line. At the end of the cycle, all events are reset and we respond to the next user event.
- In event-driven execution, we also run the regions left to right, making transitions where interface events are enabled; however, internal events are queued to be executed immediately after the current cycle. Each event in the queue has its own cycle, and they can also add events to the end of the queue. We will not respond to further external events before having emptied the queue, so infinite loops are possible here.
Part 2: Deep versus Shallow History
When you create an initial state, you choose the history type from the panel. You can later change this if you open the properties view and select the entry state. If you have minimized this view, the icon looks like a spreadsheet or go through the menus: Window → Show View... → Other → General → Properties. Sorry, I was unaware of this great marvel in usability: you can actually right-click any element and Show Properties is at bottom of the context menu!
We want to understand when and where history is stored; in particular, assume you have a composite state within another composite state (see figure). Try to develop your mental model of how history is stored by changing the initial states of the outer composite to remember history as well as deep history. Try exiting both the inner (event "i") and outer (event "o") composites. Is deep history taken into account if we enter directly into a child state (i.e., the transition is from off to inner? Try to express your mental model of how history is stored and retrieved as a few general rules.
Press the button to see my interpretation:
- When we exit a given composite state, its history is stored in a memory associated with this state. (You can visualize that it is stored in the entry state with the H or H*).
- For deep history, a snapshot is taken of the state of its children as well. This information is not stored at each child (unless it has its own history), but at the history state of the composite in question.
- When we exit a composite state, we also exit its children (if they store history, they will also do that now); however, the converse is not true. If we leave a child state to another sibling (e.g., from inner to sleep), we have not left the parent, so even a parent with deep history will not restore the child state when we return.
- History is only retrieved when we enter a history state directly or enter a composite state with a history initial state at the boundary. If we draw an arrow from off to inner, we will bypass even the deep history of the outer state.
Part 3: Guards
Okay, this is a simple exercise. Create a small state chart showing that you can use the keyword active
. You can look at the example from last year, but I would prefer if you get into the habit of experimenting on your own. The only point to clarify is that addressing requires giving the path to the element. The path can be relative to their common container: if you add a region to the outer state in the example above, you can check whether s2 is active with the guard [active(r1.inner.r1.s2)]
. Fortunately, Yakindu can autocomplete these if you type active(
and press CTRL-Space.
Part 4. Smart switch
We will most likely not have much time for this. That's okay! Next week, we will only solve exercises. Try to think of how you would solve this one at home. We will discuss solutions next week.
The goal of this exercise is to model the behavior of a smart light switch. The light has 6 levels of brightness (from 0=switched off up to 5=max brightness). There is only one button to control it. The behavior of this smart switch can be expressed like this:
- If the light was on, then a single push and release on the button, will switch off the light,
- If the light was off, then a single push and release on the button, will switch on the light at the previous brightness level,
- One push and hold on the button makes the level of brightness increase (resp. decrease) if it was increasing (resp. decreasing) previously,
- Once the maximum (resp. minimum) level of brightness is reached the brightness level decrease (resp. increase).
Tasks:
- Create a startechart of this smart switch.
- Make some simulations.
- Add the following feature to your model: In case of double push and release, if the light is on, the brightness goes up to the maximum.
Acknowledgments. The above exercise was originally written by Emmanuel Fleury and Alexandre David (Aalborg University).