Statecharts Assignment 

Submission

  • Due Date: 10 December 2022, before 23:55.
  • Team Size: 2 (pair design/programming)!
    Note that as of the 2017-2018 Academic Year, each International student should team up with "local" (i.e., whose Bachelor degree was obtained at the University of Antwerp).
  • Checklist. You should have:
    • Transformed (a subset of) the requirements into black-box test scenarios
    • Implemented the requirements in Statechart
    • The Statechart passes the black-box test
    • Generated Python code from the statechart, and the generated code "works" with the GUI
    • Wrote report
  • Submitting your solution:
    • Only one member of each team submits a full solution. This must be a ZIP-archive that includes:
      • Your report, with filename report.html
      • All the files needed to run your solution, including the files from the "starting point" that you are not allowed to edit, and your generated Python code
    • The other team member must submit a single (plain text or HTML) file containing only the names of both team members. This will allow us to put in grades for both team members in BlackBoard.
  • Submission Medium: BlackBoard. Beware that BlackBoard's clock may differ slightly from yours. If BlackBoard is not reachable due to an (unpredicted) maintenance, you submit your solution via e-mail to the TA. Make sure all group members are in CC.
  • Contact / TA: Joeri Exelmans.

Goals

The main goal of this assignment is to familiarize yourself with Statechart modeling, simulation, testing and code generation. All this is to be done with YAKINDU Statechart Tools.

Introduction to Assignment

You will use the Statecharts formalism to model the software controller of a waterway lock. The lock connects two waterway segments with different water levels, and allows watercraft to safely navigate from one segment to another. We will assume that the water level on each side is constant (so there are no tides, like we have on the river Scheldt in Antwerp).

The Kieldrecht lock, in the Port of Antwerp. Currently (2022), the largest lock in the world.

When the lock's water level is equal to the water level on one of its sides, the doors on that side may be safely opened. There is also a traffic light on each side, indicating whether watercraft is allowed to enter the lock. Every lock door also has a valve to let water flow from/to either side, to increase/decrease the water level in the chamber.

Our simulated lock.

In order to detect when altering the water level in the chamber has completed, the chamber is equipped with a water level sensor. However, this sensor is imperfect, and its data is noisy: the data can be understood as the hypothetical "perfect signal" with a small random error added to it. We will have to work around this issue. Furthermore, the sensor is known to break sometimes, outputting nonsense. We will also have to detect when the sensor breaks, and pause all operations until the sensor has been repaired.

Controller Requirements

  1. Initially, when the controller starts, it assumes that the water level in the lock is LOW. Then, the controller immediately opens the door on the LOW side, and sets its traffic light to green.
  2. At any time, someone may request a water level change of the lock. A water level change is handled by a fixed procedure (detailed below). Only when the water level change procedure has completed, will another water level change request have any effect.
  3. The water level change procedure is always assumed to start with one lock door open, and the traffic light green on the side of the open door. Then, the following steps are performed, in order:
    1. We wait until the traffic light has been green for at least 2 seconds. If the traffic light has already been green for longer than this, go immediately to the next step.
    2. The traffic light is set to red.
    3. After one second, the lock door is closed.
    4. After one more second, the "flow" valve of the opposite side is opened, causing the water level to begin changing.
    5. When the water level sensor reads a water level that is within 30 cm of the target level, we know that we are "nearly there". When this happens, we leave the flow valve open for one more second, then close it, and open the door at the opposite side, and set the traffic light on that side to green.
    6. Note: The reason for detecting if we are "nearly there", is because the data from the water level sensor is noisy. We therefore allow a certain margin of error.
  4. Whenever a water level change request has been received, the controller must notify its environment that this request has been received, with the event "setRequestPending(true)" (see also next section). When a water level change has completed, again the controller must notify its environment with the event "setRequestPending(false)", to indicate that it is ready to take another request.
  5. The controller must detect water level sensor failures at all times. We consider the water level sensor to fail, when a large enough discontinuity in its output occurs. This "large discontinuity" is a 'jump' (positive or negative) of more than 100 cm, compared to the previous value of the sensor.
  6. When a water level sensor failure is detected, it must be responded to by:
    1. Going immediately to the "emergency mode" (explained below).
    2. Outputting a "setSensorBroken" event (explained in next section).
  7. In the "emergency mode", all lock doors and all flow valves are immediately closed and remain closed, and likewise all traffic lights are set to red and stay red. We remain in this mode until someone manually hits the 'RESUME' button. (You can assume that the RESUME button will only be pressed after the water level sensor has been fixed.)
  8. While in the "emergency mode", the controller can still take water level change requests, but they cannot be completed until the "emergency mode" ends.
  9. The RESUME button ends the "emergency mode", resuming normal operations:
    • If the lock doors were open on one side when the emergency mode started (regardless of whether the traffic light was red or green), they are (immediately) re-opened, and the light set to green. If a water level change has been requested (before or during the emergency mode), the procedure restarts immediately at "Step 0": the light remains green for 2 seconds, then turns red, then after a one-second delay the doors close, etc.
    • If the lock doors were closed (because we were in the middle of a water level change procedure), then this procedure is resumed, at "Step 3": re-opening the flow valve after a one-second delay.

Controller Interface

Overview of the system and its environment.

The controller is to be implemented as a Statechart, and therefore can only interact with the plant and the environment through discrete input and output events.

Plant interface

Input eventReceived when...
waterLvl(integer) Happens when the water level sensor has a new reading. The integer parameter contains the measured water level, in centimeters. In the Python GUI, this event happens periodically (every 20ms), but you can assume that this event can occur at any time.

Note: When testing your Statechart in YAKINDU (either through unit testing or interactive simulation), the waterLvl event, like all other input events, will not be automatically raised. You will have to raise it at certain (crucial) times (but not every 20ms, because that's not realistic), and specify a realistic parameter value for it.
Output eventEffect
openDoors(integer) Opens the lock doors on one side.
closeDoors(integer) Closes the lock doors on one side.
openFlow(integer) Opens the flow valve on one side.
closeFlow(integer) Closes the flow valve on one side.
greenLight(integer) Sets the traffic light to green on one side.
redLight(integer) Sets the traffic light to red on one side.
Note: The integer parameter for the events openDoors, closeDoors, openFlow, closeFlow, greenLight and redLight indicates the side of the lock this action should apply to. Allowed values are 0 (the LOW water side) and 1 (the HIGH water side). In the Statechart interface, the integer constants LOW and HIGH have been declared, so you can (and should) use these, instead of the values 0 and 1.

Environment interface

Input eventReceived when...
requestWaterLvlChange Happens when a water level change is requested, e.g., by a lock operator.
resume After having detected a broken water level sensor, this event indicates that the water level sensor has been repaired, and normal operation can be resumed.

Output eventEffect
setSensorBroken Notifies the "environment" that a broken water level sensor has been detected. This event may be used to automatically contact a repair(wo)man.

In the Python GUI, this event enables the "RESUME" button.
setRequestPending(boolean) Notifies the "environment" that a new "water level change request" is has been accepted (if the boolean parameter is "true"), or that handling the current "water level change request" has completed (if the boolean parameter is "false").

In the Python GUI, this event enables or disables the "Change water level" button.

Testing your solution

Mandatory: Black-Box Testing

As part of the assignment, you are required to write a black-box test for your Statechart model.

With black-box testing, you can automatically run a series of specific scenarios, where you can:

  • Raise input events
  • Let time pass
  • Assert that certain output events are raised (or not raised)
  • (Read the values of interface variables - not a part of this year's assignment)

At a minimum, you must write three scenarios (as @Test operations), that cover (a subset of) the requirements. You must include the full code of these three scenarios in your report, and explain which parts of the requirements they cover.

However, we strongly encourage you to write more test scenarios that cover all of the requirements, as part of doing "test-driven development" (explained below). But even if you have more scenarios, you only have to explain three scenarios in your report.

As part of your evaluation, I will run my black-box test on your solution!

Optional: White-Box Testing

YAKINDU's testing framework also allows white-box testing. In a white-box test, you can do all the things you can do in a black-box test, but additionally, you can:

  • Check which states are active
  • Read the values of internal variables.

You may find this useful (e.g., when debugging), but white-box testing "breaks" the abstraction of the Statechart's interface.

YAKINDU does not distinguish between white- or black-box testing. We consider a test to be "black-box" when we restrict ourselves to testing the Statechart only through its interface.

Report

You are also required to write a small (HTML) report.

At the beginning, you list the following things:

  • The names and student IDs of the team members
  • The amount of time spent working on the project: Please be honest, this helps us estimate the workload for future assignments.

Then, in a structure you are free to choose, describe:

  • Your workflow: How did you work together? (pair programming / divided the work / ...) In what order did you implement different features? Encountered any difficulties?
  • Three scenarios that you implemented as black-box test (including the full code of these scenarios), and an explanation of the requirements they cover.
  • An overview of your final solution (but please do not describe every tiny detail!)

Include screenshots where appropriate: A picture is worth a thousand words!

Suggested Workflow

We suggest that you do incremental test-driven development, where you repeat the following steps:

  1. Select a feature or requirement to implement.
  2. Implement a (black-box) test for this feature.
  3. Implement the feature in your Statechart model.
  4. Verify if the tests pass. If not:
    1. Understand why it does not pass, maybe running YAKINDU's interactive debugger to get more insight into what is going on.
    2. Make further changes to your test or model.
  5. Extend your report, documenting what you did, problems encountered, etc.

For groups, we recommend pair programming (or rather, pair modeling).

Getting started

Download and install the latest version of YAKINDU Statechart Tools and register for a free academic (Professional) license, with your university e-mail address. You will be automatically e-mailed a license key that will remain valid for 3 months.

If this is not the first time that you are requesting a free license from YAKINDU, your request will sometimes be (manually) reviewed, resulting in a delayed response, of a few hours, up to a few days.

Download the Mosis22StartingPoint.zip archive. Import this archive as a project into your YAKINDU workspace. It contains the following files, which you must edit:

  • LockControllerTest.sctunit The starting point for writing a black-box unit test for the Lock Controller statechart. This file already includes one (very simple) test scenario, that you should not delete! You must extend this file with more test scenarios.
  • LockController.ysc The starting point for the Lock Controller Statechart model. The Statechart interface (the left panel) has already been defined. Do no add/remove input and output events! But it is allowed (in fact, required, to solve this assignment) to add internal event(s) and/or internal variable(s).

The archive also contains the following files, which you must not edit:

  • WaterLevelSimulator.ysc A Statechart that updates the water level in the chamber, based on which lock valves are currently opened.
  • CodeGen.sgen This file describes how YAKINDU should generate Python code from the *.ysc files. YAKINDU should automatically re-generate Python code whenever you edit any of the *.ysc files. If this is not working correctly, you can force YAKINDU to generate Python code, by right-clicking on CodeGen.sgen, and selecting "Generate code artifacts".
  • main.py This Python script runs the GUI simulator (with your generated Python code). To run the script, you need Python 3 (The assignment was developed with Python 3.10), and the TkInter Python library (included with most Python distributions).
  • src/ A directory containing some Python libraries needed to run the above Python script.
  • srcgen/ A directory containing Python code generated from your Statechart. The files in this directory will be overwritten by YAKINDU each time you generate code.

Tips

The assignment has been designed specifically to encourage use of as many Statechart features as possible:

  • composite states
  • orthogonal states
  • timed transitions
  • guard conditions
  • transition actions
  • enter/exit actions
  • internal variables
  • internal events
  • history

Make sure you understand these features, and use them, where you think they are appropriate.

Known Bugs/Curiosities in YAKINDU

Unit testing simultaneous RTC steps

(Still known to be a bug in Nov 2022)
When two RTC steps fire at the exact same time, in a unit test, you can only observe the output events raised by one of them. In the following Statechart:

The unit test fails:

More details in the following document: yakindu-unit-test.pdf
YAKINDU project that replicates the bug: KnownBug.zip

Unit testing multiple scenarios in a single operation

You should not test multiple scenarios in a single @Test operation:

But instead write a @Test operation for every scenario:

Additional Material

Maintained by Hans Vangheluwe. Last Modified: 2023/05/08 02:53:18.