Moddy Finite State Machines¶
Finite State Machine¶
-
class
moddy.fsm.
Fsm
(dict_transitions, parent_fsm=None)[source]¶ A finite state machine. Subclass your FSM from this class.
Example:
class Computer(Fsm): def __init__(self): transitions = { '': [('INITIAL', 'off')], 'off': [('PowerApplied', 'standby')], 'standby': [('PowerButtonPressed', 'normal_op')], 'normal_op': [('PowerButtonPressed', 'standby'), ('OsShutdown', 'standby')], 'any': [('PowerRemoved', 'off')] } super().__init__( dictTransitions=transitions )
The special ANY state means that the transitions can be initiated from ANY state. The special INITIAL event must be in the ‘’ (uninitialized) state and specifies the INITIAL transistion which is triggered by
start_fsm()
.You can define entry and exit method that are executed when a state is entered or left. These methods must follow the naming convention
state_<statename>_<entry/exit>
They don’t need to exist. They are called only if they are defined.Note that entry and exit actions are NOT called at self transitions (transitions to the current state):
# Off actions def state_off_entry(self): print("state_off_entry") def state_off_exit(self): print("state_off_exit")
You can also define a “do” Method that is invoked
after the “Entry” methode
at self transistions to the state
These methods must follow the naming convention
state_<statename>_do
Such routines can be also defined for the special ANY state. If they exist they are called at the entry or exit or self transitions to/from any state.
Use the fsm as follows:
comp = Computer() comp.start_fsm() # sets the state machine to its initial state comp.event('PowerApplied') print("State %s" % comp.state) comp.event('PowerButtonPressed') print("State %s" % comp.state) comp.event('PowerRemoved') print("State %s" % comp.state)
You can call
exec_state_dependent_method()
to execute a state specific method of the fsm. e.g.exec_state_dependent_method('msg', 123)
callsstate_<currentStateName>_msg( 123 )
(e.g. the simFsmPart uses it to execute the _msg and _expiration functions)
Hierarchically Nested State Support
https://en.wikipedia.org/wiki/UML_state_machine#Hierarchically_nested_states
Rules: Nested states are defined by the user in the transition list:
Main FSM:
transitions = { '': [('INITIAL', 'off')], 'off': [('PowerApplied', 'standby')], 'standby': [('PowerButtonPressed', 'normal_op')], 'normal_op': [ ####### NESTED FSM ('fsm-Name', Class-Name) ('fsm-name' , subfsm), ('PowerButtonPressed', 'standby'), ('OsShutdown', 'standby')], 'any': [('PowerRemoved', 'off')] }
A nested FSM is instantiated when the upper level state is entered
A nested FSM cannot exit
A nested FSM receives all events from the upper level FSM. If the event is not known in the nested FSM, it is directed to the upper FSM. Events that are known in the nested FSM are NOT directed to upper FSM
If the upper state exits, the exit action of the current states (first, the state in the nested fsm, then the upper fsm) are called. Then the nested fsm is terminated.
Orthogonal nested states are also supported. Meaning, multiple nested fsms exist in parallel. Just enter multiple subFsms in the transition list of a state.
For nested statemachines, the following methods are usefull:
top_fsm()
gives you the reference to the top level Fsm. E.g. to fire an event to the top Fsm.moddy_part()
gives you the moddy part where the state machine is contained, regardless of the fsm nesting level
- Parameters
-
event
(ev_name)[source]¶ Execute an Event in the ANY and current state.
- Parameters
ev_name – event to execute
- Raises
AssertionError – if the current state is None.
- Returns
True if the event causes a state change, False if not.
-
exec_state_dependent_method
(method_name, deep, *args, **kwargs)[source]¶ Execute the state specific methods:
The method
self.state_any_<method_name>(*args,**kwargs)
is called if it exists.The method
self.state_<stateName>_<method_name>(*args,**kwargs)
is called if it exists.- Parameters
method_name – method name to call
deep – if True, then for each currently active sub_fsm, the _exec_state_method is called
- Returns
True if at least one method exists
-
has_event
(ev_name)[source]¶ check if the event is known by the fsm or a currently active statemachine.
- Returns
True if event is known by the fsm or a currently active statemachine
-
moddy_part
()[source]¶ return a reference of the moddy part this fsm is contained in (regardless of the fsm nesting level). return None if it is not included in a moddy part
Moddy Part using a Finite State Machine¶
-
class
moddy.fsm_part.
SimFsmPart
(sim, obj_name, fsm, parent_obj=None, status_box_repr_map=None)[source]¶ A moddy part with a state machine All simulator events are directed to the fsm.
- Parameters
sim – Simulator instance
obj_name – part name
fsm (Fsm) – the state machine (Fsm class) object created by caller
parent_obj – parent part. None if part has no parent. Defaults to None
statusBoxReprMap (dict) –
defines how each state is shown in sequence diagrams’ status boxes Must be a dictionary with the state names as keys. The values must be a tuple of
text to display (None if org. state name shall be used)
appearance: The colors of the status box, see setStatIndication()
-
create_ports
(ptype, list_port_names)[source]¶ Convinience functions to create multiple ports at once.
- Parameters
ptype – Type of ports, must be one of ‘in’, ‘out’ or ‘io’
list_port_names (list) – list of port names to create
The function creates for each port a member variable with this name in the part.