The application tests threaded code generated by the editor of hierarchical state machines. The original scheme can be seen in the attached movie. It's another model of a switch affected by two events: TURN and RESET. The first switches two states ON and OFF, the second resets the state machine to the OFF state regardless of what state it was in before.
The editor's Planner module was supplemented with Java code generator, which automatically generates the Switch_resetHelper.java file with the class of the same name. A core has also been added to the application, which services the launch of threaded code and the impact of events on it. This is a set of several very simple classes: EventWrapper, which describes and keep an event, QHsmHelper with the IQHsmStateMachineHelper interface, which contains a container of threaded codes and ensures its execution under the influence of events, ThreadedCodeExecutor - a class that ensures the launch of threaded code for a specific state and event.
The generated Switch_resetHelper.java file is a skeleton for the logical part of the application, namely the list and bodies of empty transfer functions that can and should be filled with some content. For example, with trace elements in the simplest case. Some functions may not be used and should be deleted or commented out:
// Class Switch_resetHelper automatically generated at 2024-12-15 13:06:03
package com.widget.switchtc;
import java.util.List;
public class Switch_resetHelper {
private final QHsmHelper helper_ = new QHsmHelper("switch");
public Switch_resetHelper() {
createHelper();
}
// void switchEntry(Object data) {
// }
//
// void switchInit(Object data) {
// }
private void offEntry(Object data) {
System.out.println("OFF");
}
private void offReset(Object data) {
System.out.println("@RESET");
}
// void offExit(Object data) {
// }
private void offTurn(Object data) {
System.out.println("OFF: TURN");
}
private void onEntry(Object data) {
System.out.println("ON ");
}
// void onExit(Object data) {
// }
private void onTurn(Object data) {
System.out.println("ON : TURN");
}
public void init() {
helper_.post("init");
}
public void run(final String eventName) {
helper_.post(eventName);
}
public String state() {
return helper_.getState();
}
private void createHelper() {
helper_.insert("switch", "init", new ThreadedCodeExecutor(helper_, "off", List.of(
// this::switchEntry,
// this::switchInit,
this::offEntry
)));
helper_.insert("off", "RESET", new ThreadedCodeExecutor(helper_, "off", List.of(
this::offReset,
// this::offExit,
// this::switchInit,
this::offEntry
)));
helper_.insert("off", "TURN", new ThreadedCodeExecutor(helper_, "on", List.of(
this::offTurn,
this::onEntry
)));
helper_.insert("on", "RESET", new ThreadedCodeExecutor(helper_, "off", List.of(
this::offReset,
// this::onExit,
// this::offExit,
// this::switchInit,
this::offEntry
)));
helper_.insert("on", "TURN", new ThreadedCodeExecutor(helper_, "off", List.of(
this::onTurn,
// this::onExit,
// this::offExit,
// this::switchInit,
this::offEntry
)));
}
}
The application does not contain activity, so it is impossible to run it on a phone or tablet. Can run the unit test testSwitch(), which traces the state machine:
public class ExampleUnitTest {
@Test
public void testSwitch() {
Switch_resetHelper hsmHelper = new Switch_resetHelper();
assertEquals(hsmHelper.state(), "switch");
hsmHelper.init();
assertEquals(hsmHelper.state(), "off");
hsmHelper.run("TURN");
assertEquals(hsmHelper.state(), "on");
hsmHelper.run("RESET");
assertEquals(hsmHelper.state(), "off");
hsmHelper.run("TURN");
assertEquals(hsmHelper.state(), "on");
hsmHelper.run("TURN");
assertEquals(hsmHelper.state(), "off");
hsmHelper.run("RESET");
assertEquals(hsmHelper.state(), "off");
}
}
Result
> Task :app:testDebugUnitTest
OFF
OFF: TURN
ON
@RESET
OFF
OFF: TURN
ON
ON : TURN
OFF
@RESET
OFF
BUILD SUCCESSFUL in 13s
20 actionable tasks: 1 executed, 19 up-to-date
Build Analyzer results available
12:05:23: Execution finished ':app:testDebugUnitTest --tests "com.widget.switchtc.ExampleUnitTest.testSwitch"'.