Belle II Software development
state_machine.py
1
8import basf2 as b2
9from caf.state_machines import Machine, State
10
11# We set up a bunch of function callbacks to show the ordering of evaluation
12# Notice that we always pass **kwargs so that they have access to anything that
13# can be passed in.
14
15
16def print_msg_before(**kwargs):
17 """
18 Callbacks on transitions have access to keyword arguments that you can
19 specify when calling a transition. But remember that all kwargs are passed
20 to ALL transition callbacks. Including both the before and after callbacks
21 """
22 b2.B2INFO(kwargs["msg_before"])
23
24
25def print_msg_after(**kwargs):
26 """
27 Have to have a different kwarg name, otherwise the same argument from the
28 'before' callback will be used
29 """
30 b2.B2INFO(kwargs["msg_after"])
31
32
33def enter_new_state(**kwargs):
34 """
35 Enter and exit callbacks have access to the prior and new state objects but NOT
36 the transition arguments.
37 """
38 b2.B2INFO(f"Entering state {kwargs['new_state'].name} from state {kwargs['prior_state'].name}")
39
40
41def exit_old_state(**kwargs):
42 b2.B2INFO(f"Exiting state {kwargs['prior_state'].name} to state {kwargs['new_state'].name}")
43
44
45def condition_true(**kwargs):
46 b2.B2INFO("Evaluating conditions")
47 return True
48
49
50# Now build up a machine with some basic states and transitions between them
51m1 = Machine()
52m1.add_state(State("start", enter=enter_new_state, exit=exit_old_state)) # Can use a state object to add new ones
53m1.add_state("running", enter=enter_new_state, exit=exit_old_state) # Don't have to use a state object though
54m1.add_state("end", enter=enter_new_state, exit=exit_old_state)
55
56m1.add_transition(trigger="begin", source="start", dest="running",
57 conditions=condition_true, before=print_msg_before, after=print_msg_after)
58m1.add_transition("finish", "running", "end",
59 conditions=condition_true, before=print_msg_before, after=print_msg_after)
60
61# have to set a start point
62m1.initial_state = "start"
63
64# Note that because we didn't specify an initial state when creating the Machine we will get an orphaned default_initial
65# state in the graph. Easily removable by hand or by adding an initial state in the Machine() initialisation.
66m1.save_graph(filename="machine_graph.dot", graphname="Machine")
67
68# Run through the states passing in arguments to callbacks
69b2.B2INFO("Currently in " + m1.state.name + " state.")
70m1.begin(msg_before="About to run", msg_after="Now Running")
71m1.finish(msg_before="Finishing", msg_after="Finished")
72b2.B2INFO("Currently in " + m1.state.name + " state.")