Hsm#

class miros.hsm.HsmEventProcessor#
augment(**kwargs)#

Used to add attributes to an hsm object

Args:

kwargs[‘other’](Mandatory other object): An another object for which you would like to add as an attribute of this object.

kwargs[‘name’](Mandatory): The name that you would like to call this attribute, this argument must be a string

kwargs[‘relationship’](Optional): Indicates if you want to also add this object as an attribute to the other class, using this object’s name. This option will only work if the other object also has an augment method that acts exactly the same as this one.

Examples alarm = HsmEventProcessor(); alarm.name = “alarm” time_keeper = HsmEventProcessor(); time_keeper.name = “time_keeper” alarm.augment(other=time_keeper, name=”time_keeper”)

assert(alarm.time_keeper == time_keeper) # will be true

inverter = HsmEventProcessor(); inverter.name = “inverter” networker = HsmEventProcessor(); networker.name = “networker” inverter.augment(other=networker, name=”net”, relationship=”mutual”)

assert(inverter.net == networker) # will be true assert(networker.inverter == inverter ) # will be true

child_state(fn_parent_state_handler)#

finds the child state of a given parent

This method will only return a child state of a given handler, if the system is in a substate of the state being called:

+---------- graph_e1_s1 -----------+
| +-------- graph_e1_s2 -------+   |
| | +------ graph_e1_s3 -----+ |   |
| | | +---- graph_e1_s4 ---+ | |   |
| | | |  +- graph_e1_s5 -+ | | |   |
| | | |  |               | | | |   |
| +-b->  |               <-----a---+
| | | |  |               | | | |   |
| | +c>  +---------------+ | | |   |
+d> | +--------------------+ | |   |
| | +------------------------+ |   |
| +----------------------------+   |
+----------------------------------+

chart = HsmEventProcessor()
chart.start_at(child_state_graph_e1_s5)
chart.child_state(graph_e1_s5) #=> graph_e1_s5
chart.child_state(graph_e1_s4) #=> graph_e1_s5
chart.child_state(graph_e1_s3) #=> graph_e1_s4
chart.dispatch(event=Event(signal=signals.D)

# chart now in state graph_e1_s2
chart.child_state(graph_e1_s5) #=> <CRASH!>
chart.child_state(graph_e1_s2) #=> graph_e1_s2
chart.child_state(graph_e1_s1) #=> graph_e1_s2 # which is wrong
dispatch(e)#

dispatches an event to a HSM.

Processing an event represents one run-to-completion (RTC) step. This code is largely based on the same processor which was written by Miro Samek in his book titled, “Practical Statecharts in C/C++: Event Driven Programming for Embedded Systems.” If you need to add features or functions add them as wrappers in inherited classes. Try not to change this code too much since it is beautifully documented within the sited book.

Args:

e (Event): The event to be dispatched to the hsm object

Returns:

None

Example::

chart = HsmEventProcessor() signals.append(“A”) chart.start_at(dispatch_graph_a1_s1) chart.dispatch(Event(signal=signals.A))

Raises:

HsmTopologyException: if a state function handler is malformed

Useful mnemonics:

S (source) Which state is the source of the arrow in the diagram?

This variable is not actually defined, but it is referenced in the comments with adjacent diagrams to keep things clear.

Example::

S == dispatch_graph_f1_s0 # in the follow state function def dispatch_graph_f1_s0(chart, e):

. elif(e.signal == signals.C):

chart.trans(dispatch_graph_f1_s22)

.

T (target) What is the source aiming at? Which state is pointed

to by the arrow in the diagram? This variable is not actually defined, but it is referenced in the comments.

This will be state handler that was an argument of the trans call:

Example::

T == dispatch_graph_f1_s22 # in the follow state function def dispatch_graph_f1_s0(chart, e):

. elif(e.signal == signals.C):

chart.trans(dispatch_graph_f1_s22)

.

S->super The super state of S, the state in which S is wrapped

within.

S->super->super.. The super..super state of S

T->super The super state of T, the state in which T is wrapped

within.

T->super->super.. The super..super state of T

self.state.fun The current state before the dispatch occurred

self.temp.fun Before the search begins, this is T, but gets overwritten
during the search process by:
  • any call to trans within state function will change this.

  • any call with a super signal will change this.

lca least common ancestor. The most outward state that S and

T have in common. It is used to determine when we have constructed the correct entry path to the target, called the tpath.

tpath A list of state functions that are found during the

trans_ process. If you call this list backwards, starting from ip you will correctly enter toward T for a given state chart topology.

ip An index into the tpath. All elements between 0 and ip

in the tpath are valid entry handlers which will be used to approach T.

iq Sometimes a bool indicating if the lac has been found,

sometimes a shadow of the ip index used to discover which topology the statechart is configured in. Only used in more advanced topologies.

topology A graph characteristic that is shared well enough across

a set of graphs that part of this search algorithm can be used to move from the S to the T. There are 8 different topologies, labeled topology_a..topology_h. If you would like to know more about them, reference the tests directory where they are drawn or the trans_ method which also has them described as diagrams in the comments.

init()#

triggers the top-most initial transition into a HSM

This method is used at the beginning of an interaction with a statechart. It jumps into the initial state, then places all of the super state functions into a tpath variable. Once this tpath is discovered, it calls the entry actions on each of the tpath items. Then it calls the init actions on the target, and if this init call requires a transition, it will perform all of the above actions again until the chart settles into its final initial state.

This algorithm limits the design topology of your chart. ‘init’ signals that are going to be followed on the chart ‘start_at’ can only climb into the chart, they can not climb out. If they do, this search routine will fail.

is_in(fn_state_handler)#

tests if a hsm is in a given state

start_at(initial_state)#

hsm = HsmEventProcessor() # build it hsm.start(starting_state_function)

top(*args)#

top most state given to all HSM; treat it as an outside function

trans(fn)#

sets a new function target and returns that transition required by engine

trans_(tpath, max_index)#

execute a transition sequence in a hsm

A helper function for the `dispatch`. It navigates through the possible supported topologies, navigating the chart just up to the point of entering the target hierarchy. The target entry path is placed into the provided tpath list, and the depth of the entry path is provided as an output of the method.

Args:
tpath: a list which will be populated with the entry path required

for the dispatch method to enter the T (target) state.

max_index: The maximum index used within the tpath list up until this

point. If more space is required, an append is used to extend the length of the tpath list, otherwise an element is assigned to a given index location.

Returns:
ip: An index into the tpath. All elements between 0 and ip in the

tpath are valid entry handlers which will be used to approach T.

If you don’t understand what S/T are, read all of the mnemonics described in the `dispatch` docstring.

To understand beyond this point you must first know what happens with the tpath, ip and iq. Consider this example:

+-------- s1---------+
| +-------s2-------+ |
| | +-----s3-----+ | |
| | | +---s4---+ | | |
| | | | +-s5-+ | | | |
| | | | T    | | | | | S
| | | | +----+ | | | | top is the lca
| | | +--------+ | | |
| | +------------+ | |
| +-+--------------+ |
++------------------++

As trans_ searches, it will place state handlers into the tpath array These state handlers will be used to enter toward the target state once the lca has been found:

            useful data <-+-> garbage data
                          |   collected in search
       +----+----+----+---+----+-----+-----+
tpath: | s5 | s4 | s3 |s2 | s1 | top | s21 |
       +----+----+----+---+-/--+-----+-----+
                            |
                            +-- ip == 4

The method that called trans_ already has a reference to the tpath so it doesn’t need to be returned. However, ip does need to be returned at it represents which state handlers will be entered.

Returning the above from this method will tell `dispatch` to enter s1, enter s2, enter s3, enter s4, enter s5.

iq is a bool, it represents if we have found the lca of S and T. It is only used later in the method and it is not used outside of the method, so we only it when needed by the search. It leave comments in the code describing its state, so you can understand what is going on.

When the method begins t == T and s == S but these variable are then clobbered in the search and over-written with new meanings. Their new meanings will be described in the comments where they are used, we will always draw our attention back to S and T and how they relate to a diagram.