The application tests threaded code generated by the editor of hierarchical state machines. The original scheme can be seen on the switch_reset.svg attached to the project. It's 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 toit code generator, which automatically create the switch_reset_helper.toit file with Switch_resetHelper and Switch_resetComposer classes inside. Unlike previously used programming languages, class Switch_resetHelper doesn't contain transfer functions, because Toit doesn't have the ability to statically initialize vectors containing class functions (methods). Therefore, class Switch_resetComposer was created in which vectors of λ-functions are created dynamically on demand via the compose method.. Class Switch_resetHelper contains function createHelper builds QHsmHelper class for processing these functions. 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 placed to the tc_core.toit file: EventWrapper, which describes and keep an event, QHsmHelper which contains a container of threaded codes and ensures its execution under the influence of events, ThreadedCodeExecutor - a class ensures the launch of threaded code for a specific state and event.
The generated switch_reset_helper.toit 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:
switch_reset_helper.toit
// Classes Switch_resetHelper & Switch_resetComposer automatically generated at 2025-01-12 08:22:38
import .tc_core show *
//////////////////////////////////////////////////
// class Switch_resetHelper
//////////////////////////////////////////////////
class Switch_resetHelper :
composer_/Switch_resetComposer := Switch_resetComposer
helper_/QHsmHelper := QHsmHelper "switch"
constructor :
create_helper
create_helper -> none :
helper_.insert "switch" "init" (ThreadedCodeExecutor helper_ "off" (composer_.compose "switch.init"))
helper_.insert "off" "RESET" (ThreadedCodeExecutor helper_ "off" (composer_.compose "off.RESET"))
helper_.insert "off" "TURN" (ThreadedCodeExecutor helper_ "on" (composer_.compose "off.TURN"))
helper_.insert "on" "RESET" (ThreadedCodeExecutor helper_ "off" (composer_.compose "on.RESET"))
helper_.insert "on" "TURN" (ThreadedCodeExecutor helper_ "off" (composer_.compose "on.TURN"))
init -> none :
helper_.post "init" 1
run eventName/string -> none :
helper_.post eventName 2
state -> string :
return helper_.get_state
//////////////////////////////////////////////////
// class Switch_resetComposer
//////////////////////////////////////////////////
class Switch_resetComposer :
// switch_entry data/any -> none :
// switch_init data/any -> none :
off_entry data/any -> none :
print "OFF"
off_reset data/any -> none :
print "@RESET"
// off_exit data/any -> none :
off_turn data/any -> none :
print "OFF: TURN"
on_entry data/any -> none :
print "ON"
// on_exit data/any -> none :
on_turn data/any -> none :
print "ON : TURN"
compose key/string -> List :
list/List := []
if key == "off.RESET" :
list.add :: | p | off_reset p
// list.add :: | p | off_exit p
// list.add :: | p | switch_init p
list.add :: | p | off_entry p
return list
if key == "off.TURN" :
list.add :: | p | off_turn p
list.add :: | p | on_entry p
return list
if key == "on.TURN" :
list.add :: | p | on_turn p
// list.add :: | p | on_exit p
// list.add :: | p | off_exit p
// list.add :: | p | switch_init p
list.add :: | p | off_entry p
return list
if key == "switch.init" :
// list.add :: | p | switch_init p
// list.add :: | p | switch_entry p
list.add :: | p | off_entry p
return list;
if key == "on.RESET" :
list.add :: | p | off_reset p
// list.add :: | p | on_exit p
// list.add :: | p | off_exit p
// list.add :: | p | switch_init p
list.add :: | p | off_entry p
return list
return list;
To test the threaded code for hierarchical state machine, need to manually create small module that ensure the launch of the application:
test_switch.toit
import .tc_core show *
import .switch_reset_helper show *
main :
switchHelper/Switch_resetHelper := Switch_resetHelper
switchHelper.init
switchHelper.run "TURN"
switchHelper.run "RESET"
switchHelper.run "TURN"
switchHelper.run "TURN"
switchHelper.run "RESET"
There are several methods can use to run the application:
Launch as a console application, using the toit execute command:
michael-k@michaelk-Inspiron-14-5420:~/toit_apps/threaded_code$ toit execute switch_test.toit
OFF
OFF: TURN
ON
@RESET
OFF
OFF: TURN
ON
ON : TURN
OFF
@RESET
OFF
michael-k@michaelk-Inspiron-14-5420:~/toit_apps/threaded_code$
On an ESP32 chip named mini, using toit run command:
michael-k@michaelk-Inspiron-14-5420:~/toit_apps/threaded_code$ toit run -d=mini switch_test.toit
2025-01-09T12:40:24.418020Z: <process initiated>
OFF
OFF: TURN
ON
@RESET
OFF
OFF: TURN
ON
ON : TURN
OFF
@RESET
OFF
2025-01-09T12:40:24.893627Z: <process terminated - exit code: 0>
michael-k@michaelk-Inspiron-14-5420:~/toit_apps/threaded_code$
On an advanced ESP32-S3 chip, using Jaguar jag run command:
micrcx@micrcx-desktop:~/toit/threaded_code$ jag run switch_test.toit
Running 'switch_test.toit' on 'reversed-area' ...
Success: Sent 37KB code to 'reversed-area'
micrcx@micrcx-desktop:~/toit/threaded_code$
Trace on monitor
[jaguar] INFO: program 962d55d5-99fe-8425-a7a7-791a4892b2bd started
OFF
OFF: TURN
ON
@RESET
OFF
OFF: TURN
ON
ON : TURN
OFF
@RESET
OFF
[jaguar] INFO: program 962d55d5-99fe-8425-a7a7-791a4892b2bd stopped