fsm.py(.html)
#!/usr/local/bin/python
"""Finite state Machine module
Create class for finite state machine. Each
instance holds a list of states, and the set
of rules of how to get from one state to the
next. This should hopefully allow consistancy
checks to be made.
"""
class fsm:
def __init__(self,
start = None, # The state the machine
# will start in.
state = None, # the current state.
table = {}, # A dictionary of lists
variables = {} # The dictionary of things which
# can determine the state.
):
self.start = start
self.state = start
self.table = table
self.variables = variables
self.verbose = None
def add_state(swlf,
state,
table
):
self.table[state] = transition_list
def add_transition(self,
state,
condition,
action=None,
next_state
):
# The transtion table must be an ordered list because
# there are some tests that must be performed before
# others.
if self.table.has_key(state):
self.table[state].append((condition, action, next_state))
else:
self.table[state] = [(condition, action, next_state)]
def set_var(self,
name, # name of variable
value # value to set it to.
):
"""Set an internval variable to a value"""
if self.verbose:
print "set_var: Name %s, Value, %s" % (name, value)
self.variables[name]=value
def get_var(self,
name # name of variable
):
"""Set an internval variable to a value
Raise exception if there is a problem
"""
if self.variables.has_key(name):
return(self.variables[name])
else:
raise "Finite State Machine has no such variable", name
def set_start(self,
state # name of start state
):
"""Set the start state to be a given state"""
if self.table.has_key(state):
self.start = state
else:
raise "Illegal state", state
def check(self):
""" Check the consitency of the transiton table
"""
defined_states = [] # states for whichwe have
# defined transtions
known_states = [] # states referenced in the
# transition tables.
for state in self.table.keys():
defined_states.append(state)
for state in defined_states:
departures = [] # ways out of this state.
for tuple in self.table[state]:
(condition,action,next_state) = tuple
# Check this points to somewhere we know about.
if next_state in defined_states:
pass
else:
print "State %s has reference to undefined state %s\n" % (state, next_state)
known_states.append(next_state)
# the next state is a way out, add it to
# the list if necessary
if next_state in departures:
pass
else:
departures.append(next_state)
# Check one of the departures points out
# of this node, otherwise complain about it.
for next_state in departures:
if next_state != state:
break
else:
print "State %s has no exit points" % state
# Now check that there are no states which don't have
# pointers to them -- states we cannot get to.
for state in defined_states:
if state in known_states:
pass
else:
print "State %s defined, but never used" % state
# That is the best we can do for consitency checks
# for now.
def free_run(self):
"""set the machine running"""
if self.state == None:
raise "There is no current state for ",self
while(1):
for (condition, action, next) in self.table[self.state]:
if eval(condition):
if action != None:
exec action
self.state = next
break
def reset(self):
""" set the state to the start state."""
self.state = self.start
def step(self):
""" make a transition from a state to the next.
make a transition from the current state
to the next state (maybe the same state)
This function is needed if we have more than
one instance of the class in a non-threaded
program, so each instance can be stepped.
"""
if self.state == None:
raise "There is no current state for " % self
for (condition, action, next) in self.table[self.state]:
if self.verbose:
print "Condition %s, Action %s, Next %s" % (condition, action, next)
if eval(condition):
if action != None:
exec action
self.state = next
break