Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
239 changes: 239 additions & 0 deletions Domain/FSM/FSM.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
#!/usr/bin/env python

"""
This file contain the FSM class and the SCXMLToFSM function.
The FSM class allows to model a Finite State Machine and to simulate the transitions.
The FSM class uses the SCXMLToFSM function to translate a SCXML file into a dictionary compatible with the initFromSCXML FSM class method .
A FSM instance can be initialized in two diffrent ways:

FSM = FSM('On', {'start':'On', 'target':'Off', 'event':'1', 'send':'1'})

or

FSM = FSM()
FSM.initFromSCXML('FSM.xml')

The file FSM.xml is exported from the QFSM software only for the free text mode (http://qfsm.sourceforge.net/).
The next state and the output are obtained using the 'next' method:

FSM.next('1') -> ('Off', '1')
"""

from lxml import etree

import copy
import os, sys

__author__ = "Laurent Capocchi"
__copyright__ = "Copyright 2016, The TIC Project"
__credits__ = ["Laurent Capocchi"]
__license__ = "GPL"
__version__ = "1.0.1"
__maintainer__ = "Laurent Capocchi"
__email__ = "capocchi@univ-corse.fr"
__status__ = "Production"

class FSM():
""" Finit State Machine class
"""

def __init__(self, initState=None, transitionDict=None):
""" Constructor.

initstate is the inital state of the FSM
transititonDcit is the state transition table that defines for all transition:
start: the starting state
target: the ending state
send: the output associated with the transition
event: the event that trigger the transition
"""
self._initstate = initState
self._transitiondict = transitionDict

self._currentstate = self._initstate
self._currentoutput = None
self._states = []
self._events = []

def setTransitionDict(self, val):
""" set the state transition table
"""
self._transitiondict = val

def getTransitionDict(self):
""" get the state transition table
"""
return self._transitiondict

def setInitState(self, val):
""" set the init state with the val value
"""
self._initstate = val

def getInitState(self):
""" return the init state
"""
return self._initstate

def getCurrentState(self):
""" return the current state
"""
return self._currentstate

def setCurrentState(self, s):
""" set the current state
"""
self._currentstate = s

def getCurrentOutput(self):
""" return the current output
"""
return self._currentoutput

def setCurrentOutput(self, val):
""" set the current output
"""
self._currentoutput = val

def getStates(self):
"""
"""
return self._states

def setStates(self, states):
"""
"""
self._states = states

def setEvents(self, events):
"""
"""
self._events = events

def getEvents(self):
"""
"""
return self._events

def addStates(self, s):
""" Add the state s into the state list
"""
if not s in self._states:
self._states.append(s)

def addEvents(self, evt):
""" Add event evt to the event list
"""
if not evt in self._events:
self._events.append(s)

def initFromSCXML(self, scxml):
""" Init FSM form scxml exported from QFSM (only for free text FSM)
"""
D = SCXMLtoFSM(scxml)
if D:
self.setInitState(D['initialstate'])
self.setCurrentState(self.getInitState())
self.setTransitionDict(D['transitions'])
self.setStates(D['states'])
self.setEvents(D['events'])

def isCurrentState(self, s):
""" return True if state s is the current state
"""
return self.getCurrentState() == s

def isInstates(self, s):
""" return True if s is in the state list
"""
return s in self.getStates()

def isInEvents(self, e):
""" return True if e is in the event list
"""
return e in self.getEvents()

def next(self, event=None):
""" return the next state if event is received according to the state transition table
"""

transitionDict = self.getTransitionDict()
currentState = self.getCurrentState()
out = []

if transitionDict:
self._currentoutput = None
for d in transitionDict:
if d['start'] == currentState and d['event'] == event:
self.setCurrentState(d['target'])
#self.setCurrentOutput(d['send'])
out.append(d['send'])
#break
self.setCurrentOutput(out)
return (self.getCurrentState(), self.getCurrentOutput())

def SCXMLtoFSM(scxml):
"""
"""

### test if the first arg is a file
if not os.path.isfile(scxml):
sys.stdout.write("first arg is not a file")
return None
elif not (scxml.endswith("xml") or scxml.endswith("scxml")):
sys.stdout.write("arg is not a xml file")
return None
else:
D = {'states':[], 'events':[]}
TransitionsList = []
tree = etree.parse(scxml)
for node in tree.iter():
if 'initialstate' in node.attrib.keys():
D['initialstate'] = node.attrib['initialstate']
else:
if type(node.tag) is str:
if 'state' in node.tag:
s = node.attrib['id']
d = {'start':s}
D['states'].append(s)
elif 'transition' in node.tag:
d.update(node.attrib)
event = node.attrib['event']
if not (event in D['events']):
D['events'].append(event)
if node.getchildren() == []:
d['send']= None
TransitionsList.append(copy.copy(d))
elif 'send' in node.tag:
d['send']=node.attrib['event']
TransitionsList.append(copy.copy(d))

D['transitions'] = TransitionsList

return D

if __name__ == '__main__':

print(SCXMLtoFSM("scxml\FSM.xml"))

FSM1 = FSM()
FSM1.initFromSCXML("scxml\FSM.xml")
print ("initial state ",FSM1.getCurrentState())

print ("send 1 ", FSM1.next('1'))
print ("send 0 ", FSM1.next('0'))
print ("send 0 ", FSM1.next('0'))
print ("send 1 ", FSM1.next('1'))

FSM2 = FSM()
FSM2.initFromSCXML("scxml\FSM_SC_DC.xml")
print ("initial state ",FSM2.getCurrentState())
print ("states ", FSM2.getStates())
print ("events ", FSM2.getEvents())

print(FSM2.getTransitionDict())

print ("send ON ", FSM2.next('ON'))
print ("send OFF ", FSM2.next('OFF'))
print ("send DC ", FSM2.next('DC'))
print ("send ON ", FSM2.next('ON'))
Binary file added Domain/FSM/QFSM.amd
Binary file not shown.
2 changes: 2 additions & 0 deletions Domain/FSM/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
__all__=[
]
67 changes: 67 additions & 0 deletions Domain/FSM/fsm/SC_DC.fsm
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version='1.0'?>
<!DOCTYPE qfsmproject SYSTEM 'qfsm.dtd'>
<qfsmproject version="0.54" author="Qfsm">
<machine nummooreout="0" transfontitalic="0" draw_it="1" statefontsize="8" transfont="Helvetica" statefontitalic="0" author="capocchi" description="Finite State Machine to model the simple and double clic problem." version="0.1" name="FSM_SC_DC" arrowtype="1" numbits="2" statefontweight="50" statefont="Helvetica" numin="0" transfontsize="8" transfontweight="50" type="2" numout="0" initialstate="0">
<outputnames_moore></outputnames_moore>
<inputnames></inputnames>
<outputnames></outputnames>
<itransition ypos="107" endx="78" xpos="18" endy="107"/>
<state pencolor="0" exit_actions="" radius="40" description="" finalstate="0" entry_actions="" moore_outputs="" ypos="107" code="0" xpos="118" linewidth="1">On</state>
<state pencolor="0" exit_actions="" radius="40" description="" finalstate="0" entry_actions="" moore_outputs="" ypos="107" code="1" xpos="548" linewidth="1">Off</state>
<state pencolor="0" exit_actions="" radius="40" description="" finalstate="0" entry_actions="" moore_outputs="" ypos="324" code="2" xpos="305" linewidth="1">DC</state>
<transition c1x="274.9841814660031" c2y="124.8435980477433" c1y="122.5323550745231" description="" straight="1" type="2" ypos="120.2211121013029" endx="513.4488439640627" xpos="155.7518502169733" endy="127.1548410209635" c2x="394.2165127150329">
<from>0</from>
<to>1</to>
<inputs default="0" any="0" invert="0">OFF</inputs>
<outputs>OFF</outputs>
</transition>
<transition c1x="55.72893824183663" c2y="13.40048584525005" c1y="4.421664726361428" description="" straight="1" type="2" ypos="68.59999999999999" endx="134.1033464491136" xpos="106.8" endy="70.38467215577853" c2x="193.094147241944">
<from>0</from>
<to>0</to>
<inputs default="0" any="0" invert="0">ON</inputs>
<outputs></outputs>
</transition>
<transition c1x="193.1302207491063" c2y="237.9963425029528" c1y="185.7854480280748" description="" straight="1" type="2" ypos="133.5745535531968" endx="283.5979167526262" xpos="147.8963727473464" endy="290.2072369778309" c2x="238.3640687508662">
<from>0</from>
<to>2</to>
<inputs default="0" any="0" invert="0">DC</inputs>
<outputs>DC</outputs>
</transition>
<transition c1x="390.9693203038069" c2y="88.99823222485283" c1y="91.38856006177497" description="" straight="1" type="2" ypos="93.77888789869712" endx="152.411661345367" xpos="510.2481497830268" endy="86.60790438793069" c2x="271.6904908245869">
<from>1</from>
<to>0</to>
<inputs default="0" any="0" invert="0">ON</inputs>
<outputs>ON</outputs>
</transition>
<transition c1x="480.9482424080637" c2y="9.954403224895572" c1y="7.480847050267684" description="" straight="1" type="2" ypos="69.17253602780534" endx="562.3540031377437" xpos="534.9968092595581" endy="69.66419153250268" c2x="618.5843619122808">
<from>1</from>
<to>1</to>
<inputs default="0" any="0" invert="0">OFF</inputs>
<outputs></outputs>
</transition>
<transition c1x="450.6881865572717" c2y="235.3821879561259" c1y="181.1585656658813" description="" straight="1" type="2" ypos="126.9349433756367" endx="325.4215501662175" xpos="513.3215047527988" endy="289.6058102463706" c2x="388.0548683617445">
<from>1</from>
<to>2</to>
<inputs default="0" any="0" invert="0">DC</inputs>
<outputs>DC</outputs>
</transition>
<transition c1x="408.067755591199" c2y="441.8717497571369" c1y="385.4576094344132" description="" straight="1" type="2" ypos="352.6797967525772" endx="307.9247031830044" xpos="332.8831357316723" endy="363.8929330996271" c2x="282.4999864624285">
<from>2</from>
<to>2</to>
<inputs default="0" any="0" invert="0">DC</inputs>
<outputs></outputs>
</transition>
<transition c1x="214.0861011468298" c2y="202.5757922425297" c1y="262.955624992166" description="" straight="0" type="2" ypos="316.933437488249" endx="123.6568542494924" xpos="265.6291517202446" endy="146.5979797464467" c2x="175.1999048229072">
<from>2</from>
<to>0</to>
<inputs default="0" any="0" invert="0">ON</inputs>
<outputs>ON</outputs>
</transition>
<transition c1x="409.5475203593209" c2y="201.7950989585625" c1y="257.0158325025308" description="" straight="1" type="2" ypos="312.2365660464991" endx="542.1802403802068" xpos="343.231160348878" endy="146.5743654145941" c2x="475.8638803697638">
<from>2</from>
<to>1</to>
<inputs default="0" any="0" invert="0">OFF</inputs>
<outputs>OFF</outputs>
</transition>
</machine>
</qfsmproject>
86 changes: 86 additions & 0 deletions Domain/FSM/fsm/SC_DC_e1_e2.fsm
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?xml version='1.0'?>
<!DOCTYPE qfsmproject SYSTEM 'qfsm.dtd'>
<qfsmproject version="0.54" author="Qfsm">
<machine nummooreout="0" transfontitalic="0" draw_it="1" statefontsize="8" transfont="Helvetica" statefontitalic="0" author="capocchi" description="Finite State Machine to model the simple and double clic problem with e1 and e2 as events" version="0.1" name="FSM_e1_e2" arrowtype="1" numbits="2" statefontweight="50" statefont="Helvetica" numin="0" transfontsize="8" transfontweight="50" type="2" numout="0" initialstate="0">
<outputnames_moore></outputnames_moore>
<inputnames></inputnames>
<outputnames></outputnames>
<itransition ypos="103" endx="120" xpos="60" endy="103"/>
<state pencolor="0" exit_actions="" radius="40" description="" finalstate="0" entry_actions="" moore_outputs="" ypos="103" code="0" xpos="160" linewidth="1">ON</state>
<state pencolor="0" exit_actions="" radius="40" description="" finalstate="0" entry_actions="" moore_outputs="" ypos="112" code="1" xpos="503" linewidth="1">OFF</state>
<state pencolor="0" exit_actions="" radius="40" description="" finalstate="0" entry_actions="" moore_outputs="" ypos="288" code="2" xpos="496" linewidth="1">DC_ON</state>
<state pencolor="0" exit_actions="" radius="40" description="" finalstate="0" entry_actions="" moore_outputs="" ypos="273" code="3" xpos="142" linewidth="1">DC_OFF</state>
<transition c1x="289.3407087357664" c2y="94.72026183821762" c1y="97.2860812107086" description="" straight="1" type="2" ypos="99.85190058319958" endx="468.2702743150217" xpos="199.8759259461388" endy="92.15444246572665" c2x="378.805491525394">
<from>0</from>
<to>1</to>
<inputs default="0" any="0" invert="0">e1</inputs>
<outputs>off</outputs>
</transition>
<transition c1x="278.2884917569862" c2y="132.4636020404552" c1y="133.9065227062914" description="" straight="1" type="2" ypos="135.3494433721276" endx="467.8117394569549" xpos="183.5268679070018" endy="131.020681374619" c2x="373.0501156069706">
<from>0</from>
<to>1</to>
<inputs default="0" any="0" invert="0">e2</inputs>
<outputs>off</outputs>
</transition>
<transition c1x="152.286497880503" c2y="202.9821006373691" c1y="172.9089144480386" description="" straight="1" type="2" ypos="142.8357282587081" endx="144.1023533249106" xpos="156.3785701582993" endy="233.0552868266996" c2x="148.1944256027068">
<from>0</from>
<to>3</to>
<inputs default="0" any="0" invert="0">e1e2</inputs>
<outputs>dc_off</outputs>
</transition>
<transition c1x="504.1449978766609" c2y="216.1152052049318" c1y="183.9986923124975" description="" straight="1" type="2" ypos="151.8821794200633" endx="500.2992737192037" xpos="506.0678599553895" endy="248.231718097366" c2x="502.2221357979323">
<from>1</from>
<to>2</to>
<inputs default="0" any="0" invert="0">e1e2</inputs>
<outputs>dc_on</outputs>
</transition>
<transition c1x="374.0394588296801" c2y="116.8678120469647" c1y="113.259465584453" description="" straight="1" type="2" ypos="109.6511191219412" endx="195.9803263430399" xpos="463.0690250730002" endy="120.4761585094765" c2x="285.00989258636">
<from>1</from>
<to>0</to>
<inputs default="0" any="0" invert="0">e2</inputs>
<outputs>on</outputs>
</transition>
<transition c1x="387.2878186086782" c2y="77.004752178074" c1y="76.51221291751705" description="" straight="1" type="2" ypos="76.01967365696009" endx="190.8157728449876" xpos="485.5238414905235" endy="77.49729143863095" c2x="289.0517957268329">
<from>1</from>
<to>0</to>
<inputs default="0" any="0" invert="0">e1</inputs>
<outputs>on</outputs>
</transition>
<transition c1x="364.0759022707186" c2y="288.3120468813329" c1y="290.3646539621634" description="" straight="1" type="2" ypos="292.4172610429939" endx="179.7384055860453" xpos="456.2446506130552" endy="286.2594398005024" c2x="271.9071539283819">
<from>2</from>
<to>3</to>
<inputs default="0" any="0" invert="0">e1e2</inputs>
<outputs>dc_off</outputs>
</transition>
<transition c1x="475.7172251777648" c2y="178.3234974048033" c1y="215.8532229927791" description="" straight="1" type="2" ypos="253.3829485807549" endx="475.2345771766307" xpos="475.9585491783318" endy="140.7937718168274" c2x="475.4759011771977">
<from>2</from>
<to>1</to>
<inputs default="0" any="0" invert="0">e2</inputs>
<outputs>off</outputs>
</transition>
<transition c1x="528.9427649877159" c2y="177.2127595026578" c1y="219.1759912565517" description="" straight="1" type="2" ypos="261.1392230104456" endx="535.5493388482694" xpos="525.6394780574393" endy="135.2495277487639" c2x="532.2460519179928">
<from>2</from>
<to>1</to>
<inputs default="0" any="0" invert="0">e1</inputs>
<outputs>off</outputs>
</transition>
<transition c1x="275.0499345506153" c2y="266.8392658098626" c1y="266.8784892198525" description="" straight="1" type="2" ypos="266.9177126298424" endx="462.0800678397965" xpos="181.5348679060247" endy="266.8000423998728" c2x="368.5650011952059">
<from>3</from>
<to>2</to>
<inputs default="0" any="0" invert="0">e1e2</inputs>
<outputs>dc_on</outputs>
</transition>
<transition c1x="119.6850437934983" c2y="166.6297254170081" c1y="205.0357458302374" description="" straight="1" type="2" ypos="243.4417662434668" endx="128.9554399953494" xpos="115.0498456925727" endy="128.2237050037786" c2x="124.3202418944238">
<from>3</from>
<to>0</to>
<inputs default="0" any="0" invert="0">e1</inputs>
<outputs>on</outputs>
</transition>
<transition c1x="174.3728249979557" c2y="172.8258069764941" c1y="209.0044749379259" description="" straight="1" type="2" ypos="245.1831428993578" endx="181.6303036525399" xpos="170.7440856706636" endy="136.6471390150622" c2x="178.0015643252478">
<from>3</from>
<to>0</to>
<inputs default="0" any="0" invert="0">e2</inputs>
<outputs>on</outputs>
</transition>
</machine>
</qfsmproject>
Loading