An interactive state machine demo An online interactive demo of automata-based programming with DRAKON by Stepan Mitkin

updated on 18 August 2018 Share Go to the demo The source code for this demo has been generated from DRAKON diagrams. Browse the source code: https://github.com/stepan-mitkin/lift-demo DRAKON Editor (needed to open the .drn files):

http://drakon-editor.sourceforge.net/editor.html

https://github.com/stepan-mitkin/drakon_editor The unknown state machines Late in 2017, I surveyed my fellow developers. The survey had only two questions: do you know what state machines are and do you use them. The staggering 95% had no idea on the subject. One of the developers said: "I know what state machines are but I don't need to worry about them because I develop software, not hardware." It's like saying "I write C#, so I don't need the internet. It's the Java programmers who surf the internet." State machines are not limited to electronics. State machines are a universal tool for modeling behavior. Every piece of software that runs longer than a fraction of a second has behavior. Therefore, almost all programs could benefit from state machines.

The demo Press the buttons below to play with the lift.

A hierarchy of machines This demo uses several state machines to control a virtual lift. Having more than one machine is a typical situation. Most practical applications are too complex to be modeled with just one automaton. The state machines in the demo form a tree-like structure, a hierarchy. It is essential to have a hierarchy. An unrestricted net of machines, where all can connect to all, is hard to test and support. In an event-driven environment, a master machine talks to a slave machine by calling methods, as if the slave machine was a regular class. The slave machine, however, can only communicate with its master by sending messages through the event loop. The requirement to arrange machines in a tree is sometimes too strict. For practical purposes, it is okay to add some additional links between the machines. The important thing is that the graph of machines must not have cycles. A machine that sits lower in the graph must never directly call methods of the machine above it.

DRAKON makes automata-based programming practical Even though state machines are a solid concept, it is hard to use them. The mainstream programming languages do not have first-class support for state machines. If a programmer wants to make a machine, he has to follow some informal patterns in code. Such hand-made machines are better than just classes, but they are not easy to comprehend. Visualization might help. But how to draw a state machine? The traditional state machine diagrams are confusing and inconsistent. They do not give quick answers to questions like "which signals does this machine accept in this specific state?" or "which states can the machine switch to from this state?" Another problem is that the programmer often needs to manually write part of the machine in a separate file. These difficulties seem to be the reason why the software industry does not widely accept state machines. The DRAKON visual language could be a solution to these problems. A state machine can be represented with a DRAKON chart of type "silhouette". Silhouette combines state machines with decision trees. A silhouette diagram shows the states, the transitions, and the machine's decision logic in the same visual scene. As a result, working with machines becomes easier. Another benefit of using DRAKON for state machines is that DRAKON is an ergonomically optimized visual language. DRAKON diagrams are clean, predictable and consistent. How to build a state machine with DRAKON This demo shows a way to represent state machines with DRAKON silhouette diagrams. This is how to turn a DRAKON chart into a state machine: Add the "state machine" keyphrase to the Parameters icon (the rectangle at the left top corner).

Each silhouette branch becomes a state.

Every branch must have a Switch icon with the "receive" keyword. The Case icons define the signals that the machine will accept and hence the methods that the generated class will have.

The Address icons at the bottom control state switching. This way, DRAKON Editor generates one state machine class from one silhouette diagram.

The machines from the demo The Door controls the inner and outer lift doors as one. There are one internal door and several external doors, one per floor. motor.connect() method connects the inner door to one of the outer doors. The Door translates the logical "opened" and "closed" positions into coordinates and sends them to the motor. The Door can have the following states: Closed, Opening, Open, and Closing. When the door is in the Closed state, it accepts only the "open" message. Having gotten this message, the door sends a command to the motor to open the physical door and enters the Opening state. While in the Opening state, it is possible to send the "close" message to the Door and it will start closing. When the motor has fully opened the physical door, it sends the "done" message to the Door. The Door reports that it is now officially open. When the Door is in the Open state, it accepts only the "close" message. The Closing state is similar to Opening. While Closing, the Door is waiting for the "done" message from the motor to switch to the Closed state.

The Cabin translates floor numbers into coordinates and controls the motor that moves the lift cabin. A cabin can be either moving or standing still. These two possibilities make up the states of the Cabin machine: Moving and Still. Having gotten the "move" command, the Cabin sets the new target for the motor. "move" is accepted in both Moving and Still states. While the cabin is moving, it waits for the "done" message from the motor. "done" means the motor has transferred the cabin to the target floor.

The job of the Scheduler is to choose the next floor. The Scheduler makes this choice based on three pieces of information: which buttons are pressed, the direction of movement—up or down, and the current floor. The direction of movement is stored as the state: Up or Down. The current floor comes to the Scheduler in the "chooseNext" message. The knowledge about pressed buttons is kept in the slave machine "buttons". Since "buttons" is a slave machine, the Cabin can call the methods of the "buttons" machine directly. If the lift is moving up towards the fourth floor and button 3 inside the cabin is pressed, the Scheduler will decide that the lift should stop on the third floor first. But if button 3 inside the cabin is not pressed and the "Down" button on the third floor is pressed instead, the lift should skip the third floor and proceed to the fourth.

LiftMain is the king of the hierarchy in this example. LiftMain makes the decisions what to do next based on user input and events from the lift machinery. LiftMain is effectively a class because it has only one state: Ready. Here are the rules that LiftMain implements: "When the cabin stands on a floor and a button corresponding to that floor is pressed, open the door." A signal that a button is pressed comes to LiftMain in the form of a "go" message. Note that this message comes from the outside, but does not hit LiftMain directly. First, the button press event is handled by the Buttons machine. Then, it goes up to the Scheduler and then the Scheduler forwards the message to the LiftMain. Remember, that the topmost machine is responsible only for strategic decisions. Not all incoming messages should bother the boss.

A signal that a button is pressed comes to LiftMain in the form of a "go" message. Note that this message comes from the outside, but does not hit LiftMain directly. First, the button press event is handled by the Buttons machine. Then, it goes up to the Scheduler and then the Scheduler forwards the message to the LiftMain. Remember, that the topmost machine is responsible only for decisions. Not all incoming messages should bother the boss. "When a button is pressed and that button does not point to the current floor and the door is closed, go to the respective floor." This combination of conditions is handled by the same decision tree for the "go" message.

This combination of conditions is handled by the same decision tree for the "go" message. "When the door opens, close the door after 2 seconds." LiftMain finds out that the door is open after getting an "opened" message from the Cabin.

LiftMain finds out that the door is open after getting an "opened" message from the Cabin. "After the door closes, move the lift to the next scheduled floor." The Door machine notifies LiftMain that the door is closed by sending a "closed" message.

The Door machine notifies LiftMain that the door is closed by sending a "closed" message. "When the lift arrives at a floor, open the door." When the Cabin comes to a floor, it sends an "arrived" message to LiftMain.