Move python evaluator to create a python plugin containing any related python module
authorlaurent
Wed, 29 Jul 2009 15:17:10 +0200
changeset 366 cd90e4c10261
parent 365 a7f58414dea0
child 367 a76ee5307bb7
Move python evaluator to create a python plugin containing any related python module
PythonSTC.py
plugger.py
plugins/python/PythonEditor.py
plugins/python/README
plugins/python/__init__.py
plugins/python/modules/__init__.py
plugins/python/plc_python.c
plugins/python/pous.xml
plugins/python/python.py
plugins/python/python_xsd.xsd
pous.xml
runtime/PLCObject.py
targets/plc_common_main.c
targets/plc_python.c
tests/python/plc.xml
tests/python/python@python/baseplugin.xml
tests/python/python@python/python.xml
tests/python/runtime.py
--- a/PythonSTC.py	Wed Jul 29 10:49:31 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,596 +0,0 @@
-import  keyword
-import  os
-import  wx
-import  wx.stc  as  stc
-
-#----------------------------------------------------------------------
-
-"""
-This Python editor class comes from the wxPython demo, a bit tweaked
-"""
-
-#----------------------------------------------------------------------
-
-
-if wx.Platform == '__WXMSW__':
-    faces = { 'times': 'Times New Roman',
-              'mono' : 'Courier New',
-              'helv' : 'Arial',
-              'other': 'Comic Sans MS',
-              'size' : 10,
-              'size2': 8,
-             }
-elif wx.Platform == '__WXMAC__':
-    faces = { 'times': 'Times New Roman',
-              'mono' : 'Monaco',
-              'helv' : 'Arial',
-              'other': 'Comic Sans MS',
-              'size' : 12,
-              'size2': 10,
-             }
-else:
-    faces = { 'times': 'Times',
-              'mono' : 'Courier',
-              'helv' : 'Helvetica',
-              'other': 'new century schoolbook',
-              'size' : 12,
-              'size2': 10,
-             }
-
-
-#----------------------------------------------------------------------
-
-class PythonSTC(stc.StyledTextCtrl):
-
-    fold_symbols = 2
-    
-    def __init__(self, parent, ID,
-                 pos=wx.DefaultPosition, size=wx.DefaultSize,
-                 style=0):
-        stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
-
-        self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
-        self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
-
-        self.SetLexer(stc.STC_LEX_PYTHON)
-        self.SetKeyWords(0, " ".join(keyword.kwlist))
-
-        self.SetProperty("fold", "1")
-        self.SetProperty("tab.timmy.whinge.level", "1")
-        self.SetMargins(0,0)
-
-        self.SetViewWhiteSpace(False)
-        #self.SetBufferedDraw(False)
-        #self.SetViewEOL(True)
-        #self.SetEOLMode(stc.STC_EOL_CRLF)
-        #self.SetUseAntiAliasing(True)
-        
-        self.SetEdgeMode(stc.STC_EDGE_BACKGROUND)
-        self.SetEdgeColumn(78)
-
-        # Setup a margin to hold fold markers
-        #self.SetFoldFlags(16)  ###  WHAT IS THIS VALUE?  WHAT ARE THE OTHER FLAGS?  DOES IT MATTER?
-        self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
-        self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
-        self.SetMarginSensitive(2, True)
-        self.SetMarginWidth(2, 12)
-
-        if self.fold_symbols == 0:
-            # Arrow pointing right for contracted folders, arrow pointing down for expanded
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN,    stc.STC_MARK_ARROWDOWN, "black", "black")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDER,        stc.STC_MARK_ARROW, "black", "black")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB,     stc.STC_MARK_EMPTY, "black", "black")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL,    stc.STC_MARK_EMPTY, "black", "black")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND,     stc.STC_MARK_EMPTY,     "white", "black")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY,     "white", "black")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY,     "white", "black")
-            
-        elif self.fold_symbols == 1:
-            # Plus for contracted folders, minus for expanded
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN,    stc.STC_MARK_MINUS, "white", "black")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDER,        stc.STC_MARK_PLUS,  "white", "black")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB,     stc.STC_MARK_EMPTY, "white", "black")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL,    stc.STC_MARK_EMPTY, "white", "black")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND,     stc.STC_MARK_EMPTY, "white", "black")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black")
-
-        elif self.fold_symbols == 2:
-            # Like a flattened tree control using circular headers and curved joins
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN,    stc.STC_MARK_CIRCLEMINUS,          "white", "#404040")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDER,        stc.STC_MARK_CIRCLEPLUS,           "white", "#404040")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB,     stc.STC_MARK_VLINE,                "white", "#404040")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL,    stc.STC_MARK_LCORNERCURVE,         "white", "#404040")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND,     stc.STC_MARK_CIRCLEPLUSCONNECTED,  "white", "#404040")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE,         "white", "#404040")
-
-        elif self.fold_symbols == 3:
-            # Like a flattened tree control using square headers
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN,    stc.STC_MARK_BOXMINUS,          "white", "#808080")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDER,        stc.STC_MARK_BOXPLUS,           "white", "#808080")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB,     stc.STC_MARK_VLINE,             "white", "#808080")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL,    stc.STC_MARK_LCORNER,           "white", "#808080")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND,     stc.STC_MARK_BOXPLUSCONNECTED,  "white", "#808080")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
-            self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER,           "white", "#808080")
-
-
-        self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
-        self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
-        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
-
-        # Make some styles,  The lexer defines what each style is used for, we
-        # just have to define what each style looks like.  This set is adapted from
-        # Scintilla sample property files.
-
-        # Global default styles for all languages
-        self.StyleSetSpec(stc.STC_STYLE_DEFAULT,     "face:%(helv)s,size:%(size)d" % faces)
-        self.StyleClearAll()  # Reset all to be like the default
-
-        # Global default styles for all languages
-        self.StyleSetSpec(stc.STC_STYLE_DEFAULT,     "face:%(helv)s,size:%(size)d" % faces)
-        self.StyleSetSpec(stc.STC_STYLE_LINENUMBER,  "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces)
-        self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
-        self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,  "fore:#FFFFFF,back:#0000FF,bold")
-        self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,    "fore:#000000,back:#FF0000,bold")
-
-        # Python styles
-        # Default 
-        self.StyleSetSpec(stc.STC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
-        # Comments
-        self.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces)
-        # Number
-        self.StyleSetSpec(stc.STC_P_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
-        # String
-        self.StyleSetSpec(stc.STC_P_STRING, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
-        # Single quoted string
-        self.StyleSetSpec(stc.STC_P_CHARACTER, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
-        # Keyword
-        self.StyleSetSpec(stc.STC_P_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
-        # Triple quotes
-        self.StyleSetSpec(stc.STC_P_TRIPLE, "fore:#7F0000,size:%(size)d" % faces)
-        # Triple double quotes
-        self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, "fore:#7F0000,size:%(size)d" % faces)
-        # Class name definition
-        self.StyleSetSpec(stc.STC_P_CLASSNAME, "fore:#0000FF,bold,underline,size:%(size)d" % faces)
-        # Function or method name definition
-        self.StyleSetSpec(stc.STC_P_DEFNAME, "fore:#007F7F,bold,size:%(size)d" % faces)
-        # Operators
-        self.StyleSetSpec(stc.STC_P_OPERATOR, "bold,size:%(size)d" % faces)
-        # Identifiers
-        self.StyleSetSpec(stc.STC_P_IDENTIFIER, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
-        # Comment-blocks
-        self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, "fore:#7F7F7F,size:%(size)d" % faces)
-        # End of line where string is not closed
-        self.StyleSetSpec(stc.STC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces)
-
-        self.SetCaretForeground("BLUE")
-
-    def OnKeyPressed(self, event):
-        if self.CallTipActive():
-            self.CallTipCancel()
-
-        event.Skip()
-## For later use
-#        key = event.GetKeyCode()
-#        if key == 32 and event.ControlDown():
-#            pos = self.GetCurrentPos()
-#
-#            # Tips
-#            if event.ShiftDown():
-#                self.CallTipSetBackground("yellow")
-#                self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n'
-#                                 'show some suff, maybe parameters..\n\n'
-#                                 'fubar(param1, param2)')
-#            # Code completion
-#            else:
-#                #lst = []
-#                #for x in range(50000):
-#                #    lst.append('%05d' % x)
-#                #st = " ".join(lst)
-#                #print len(st)
-#                #self.AutoCompShow(0, st)
-#
-#                kw = keyword.kwlist[:]
-#                kw.append("zzzzzz?2")
-#                kw.append("aaaaa?2")
-#                kw.append("__init__?3")
-#                kw.append("zzaaaaa?2")
-#                kw.append("zzbaaaa?2")
-#                kw.append("this_is_a_longer_value")
-#                #kw.append("this_is_a_much_much_much_much_much_much_much_longer_value")
-#
-#                kw.sort()  # Python sorts are case sensitive
-#                self.AutoCompSetIgnoreCase(False)  # so this needs to match
-#
-#                # Images are specified with a appended "?type"
-#                for i in range(len(kw)):
-#                    if kw[i] in keyword.kwlist:
-#                        kw[i] = kw[i] + "?1"
-#
-#                self.AutoCompShow(0, " ".join(kw))
-#        else:
-#            event.Skip()
-
-
-    def OnUpdateUI(self, evt):
-        # check for matching braces
-        braceAtCaret = -1
-        braceOpposite = -1
-        charBefore = None
-        caretPos = self.GetCurrentPos()
-
-        if caretPos > 0:
-            charBefore = self.GetCharAt(caretPos - 1)
-            styleBefore = self.GetStyleAt(caretPos - 1)
-
-        # check before
-        if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
-            braceAtCaret = caretPos - 1
-
-        # check after
-        if braceAtCaret < 0:
-            charAfter = self.GetCharAt(caretPos)
-            styleAfter = self.GetStyleAt(caretPos)
-
-            if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
-                braceAtCaret = caretPos
-
-        if braceAtCaret >= 0:
-            braceOpposite = self.BraceMatch(braceAtCaret)
-
-        if braceAtCaret != -1  and braceOpposite == -1:
-            self.BraceBadLight(braceAtCaret)
-        else:
-            self.BraceHighlight(braceAtCaret, braceOpposite)
-            #pt = self.PointFromPosition(braceOpposite)
-            #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
-            #print pt
-            #self.Refresh(False)
-
-
-    def OnMarginClick(self, evt):
-        # fold and unfold as needed
-        if evt.GetMargin() == 2:
-            if evt.GetShift() and evt.GetControl():
-                self.FoldAll()
-            else:
-                lineClicked = self.LineFromPosition(evt.GetPosition())
-
-                if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
-                    if evt.GetShift():
-                        self.SetFoldExpanded(lineClicked, True)
-                        self.Expand(lineClicked, True, True, 1)
-                    elif evt.GetControl():
-                        if self.GetFoldExpanded(lineClicked):
-                            self.SetFoldExpanded(lineClicked, False)
-                            self.Expand(lineClicked, False, True, 0)
-                        else:
-                            self.SetFoldExpanded(lineClicked, True)
-                            self.Expand(lineClicked, True, True, 100)
-                    else:
-                        self.ToggleFold(lineClicked)
-
-
-    def FoldAll(self):
-        lineCount = self.GetLineCount()
-        expanding = True
-
-        # find out if we are folding or unfolding
-        for lineNum in range(lineCount):
-            if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
-                expanding = not self.GetFoldExpanded(lineNum)
-                break
-
-        lineNum = 0
-
-        while lineNum < lineCount:
-            level = self.GetFoldLevel(lineNum)
-            if level & stc.STC_FOLDLEVELHEADERFLAG and \
-               (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
-
-                if expanding:
-                    self.SetFoldExpanded(lineNum, True)
-                    lineNum = self.Expand(lineNum, True)
-                    lineNum = lineNum - 1
-                else:
-                    lastChild = self.GetLastChild(lineNum, -1)
-                    self.SetFoldExpanded(lineNum, False)
-
-                    if lastChild > lineNum:
-                        self.HideLines(lineNum+1, lastChild)
-
-            lineNum = lineNum + 1
-
-
-
-    def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
-        lastChild = self.GetLastChild(line, level)
-        line = line + 1
-
-        while line <= lastChild:
-            if force:
-                if visLevels > 0:
-                    self.ShowLines(line, line)
-                else:
-                    self.HideLines(line, line)
-            else:
-                if doExpand:
-                    self.ShowLines(line, line)
-
-            if level == -1:
-                level = self.GetFoldLevel(line)
-
-            if level & stc.STC_FOLDLEVELHEADERFLAG:
-                if force:
-                    if visLevels > 1:
-                        self.SetFoldExpanded(line, True)
-                    else:
-                        self.SetFoldExpanded(line, False)
-
-                    line = self.Expand(line, doExpand, force, visLevels-1)
-
-                else:
-                    if doExpand and self.GetFoldExpanded(line):
-                        line = self.Expand(line, True, force, visLevels-1)
-                    else:
-                        line = self.Expand(line, False, force, visLevels-1)
-            else:
-                line = line + 1
-
-        return line
-
-
-#----------------------------------------------------------------------
-class PythonCodeEditor(PythonSTC):
-    def __init__(self, parent):
-        PythonSTC.__init__(self, parent, -1, style=wx.BORDER_NONE)
-        self.SetUpEditor()
-
-    # Some methods to make it compatible with how the wxTextCtrl is used
-    def SetValue(self, value):
-        if wx.USE_UNICODE:
-            value = value.decode('utf-8')
-        self.SetText(value)
-        self.EmptyUndoBuffer()
-        self.SetSavePoint()
-
-    def IsModified(self):
-        return self.GetModify()
-
-    def Clear(self):
-        self.ClearAll()
-
-    def SetInsertionPoint(self, pos):
-        self.SetCurrentPos(pos)
-        self.SetAnchor(pos)
-
-    def ShowPosition(self, pos):
-        line = self.LineFromPosition(pos)
-        #self.EnsureVisible(line)
-        self.GotoLine(line)
-
-    def GetLastPosition(self):
-        return self.GetLength()
-
-    def GetPositionFromLine(self, line):
-        return self.PositionFromLine(line)
-
-    def GetRange(self, start, end):
-        return self.GetTextRange(start, end)
-
-    def GetSelection(self):
-        return self.GetAnchor(), self.GetCurrentPos()
-
-    def SetSelection(self, start, end):
-        self.SetSelectionStart(start)
-        self.SetSelectionEnd(end)
-
-    def SelectLine(self, line):
-        start = self.PositionFromLine(line)
-        end = self.GetLineEndPosition(line)
-        self.SetSelection(start, end)
-        
-    def SetUpEditor(self):
-        """
-        This method carries out the work of setting up the demo editor.            
-        It's seperate so as not to clutter up the init code.
-        """
-        import keyword
-        
-        self.SetLexer(stc.STC_LEX_PYTHON)
-        self.SetKeyWords(0, " ".join(keyword.kwlist))
-
-        # Enable folding
-        self.SetProperty("fold", "1" ) 
-
-        # Highlight tab/space mixing (shouldn't be any)
-        self.SetProperty("tab.timmy.whinge.level", "1")
-
-        # Set left and right margins
-        self.SetMargins(2,2)
-
-        # Set up the numbers in the margin for margin #1
-        self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER)
-        # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
-        self.SetMarginWidth(1, 40)
-
-        # Indentation and tab stuff
-        self.SetIndent(4)               # Proscribed indent size for wx
-        self.SetIndentationGuides(True) # Show indent guides
-        self.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
-        self.SetTabIndents(True)        # Tab key indents
-        self.SetTabWidth(4)             # Proscribed tab size for wx
-        self.SetUseTabs(False)          # Use spaces rather than tabs, or
-                                        # TabTimmy will complain!    
-        # White space
-        self.SetViewWhiteSpace(False)   # Don't view white space
-
-        # EOL: Since we are loading/saving ourselves, and the
-        # strings will always have \n's in them, set the STC to
-        # edit them that way.            
-        self.SetEOLMode(wx.stc.STC_EOL_LF)
-        self.SetViewEOL(False)
-        
-        # No right-edge mode indicator
-        self.SetEdgeMode(stc.STC_EDGE_NONE)
-
-        # Setup a margin to hold fold markers
-        self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
-        self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
-        self.SetMarginSensitive(2, True)
-        self.SetMarginWidth(2, 12)
-
-        # and now set up the fold markers
-        self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND,     stc.STC_MARK_BOXPLUSCONNECTED,  "white", "black")
-        self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "black")
-        self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER,  "white", "black")
-        self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL,    stc.STC_MARK_LCORNER,  "white", "black")
-        self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB,     stc.STC_MARK_VLINE,    "white", "black")
-        self.MarkerDefine(stc.STC_MARKNUM_FOLDER,        stc.STC_MARK_BOXPLUS,  "white", "black")
-        self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN,    stc.STC_MARK_BOXMINUS, "white", "black")
-
-        # Global default style
-        if wx.Platform == '__WXMSW__':
-            self.StyleSetSpec(stc.STC_STYLE_DEFAULT, 
-                              'fore:#000000,back:#FFFFFF,face:Courier New')
-        elif wx.Platform == '__WXMAC__':
-            # TODO: if this looks fine on Linux too, remove the Mac-specific case 
-            # and use this whenever OS != MSW.
-            self.StyleSetSpec(stc.STC_STYLE_DEFAULT, 
-                              'fore:#000000,back:#FFFFFF,face:Monaco')
-        else:
-            defsize = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT).GetPointSize()
-            self.StyleSetSpec(stc.STC_STYLE_DEFAULT, 
-                              'fore:#000000,back:#FFFFFF,face:Courier,size:%d'%defsize)
-
-        # Clear styles and revert to default.
-        self.StyleClearAll()
-
-        # Following style specs only indicate differences from default.
-        # The rest remains unchanged.
-
-        # Line numbers in margin
-        self.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2')    
-        # Highlighted brace
-        self.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00')
-        # Unmatched brace
-        self.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000')
-        # Indentation guide
-        self.StyleSetSpec(wx.stc.STC_STYLE_INDENTGUIDE, "fore:#CDCDCD")
-
-        # Python styles
-        self.StyleSetSpec(wx.stc.STC_P_DEFAULT, 'fore:#000000')
-        # Comments
-        self.StyleSetSpec(wx.stc.STC_P_COMMENTLINE,  'fore:#008000,back:#F0FFF0')
-        self.StyleSetSpec(wx.stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0')
-        # Numbers
-        self.StyleSetSpec(wx.stc.STC_P_NUMBER, 'fore:#008080')
-        # Strings and characters
-        self.StyleSetSpec(wx.stc.STC_P_STRING, 'fore:#800080')
-        self.StyleSetSpec(wx.stc.STC_P_CHARACTER, 'fore:#800080')
-        # Keywords
-        self.StyleSetSpec(wx.stc.STC_P_WORD, 'fore:#000080,bold')
-        # Triple quotes
-        self.StyleSetSpec(wx.stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA')
-        self.StyleSetSpec(wx.stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA')
-        # Class names
-        self.StyleSetSpec(wx.stc.STC_P_CLASSNAME, 'fore:#0000FF,bold')
-        # Function names
-        self.StyleSetSpec(wx.stc.STC_P_DEFNAME, 'fore:#008080,bold')
-        # Operators
-        self.StyleSetSpec(wx.stc.STC_P_OPERATOR, 'fore:#800000,bold')
-        # Identifiers. I leave this as not bold because everything seems
-        # to be an identifier if it doesn't match the above criterae
-        self.StyleSetSpec(wx.stc.STC_P_IDENTIFIER, 'fore:#000000')
-
-        # Caret color
-        self.SetCaretForeground("BLUE")
-        # Selection background
-        self.SetSelBackground(1, '#66CCFF')
-
-        self.SetSelBackground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
-        self.SetSelForeground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))
-
-    def RegisterModifiedEvent(self, eventHandler):
-        self.Bind(wx.stc.EVT_STC_CHANGE, eventHandler)
-
-
-class PythonCodePanel(wx.Panel):
-    """Panel for the 'Demo Code' tab"""
-    def __init__(self, parent, mainFrame):
-        wx.Panel.__init__(self, parent, size=(1,1))
-        self.mainFrame = mainFrame
-        self.editor = PythonCodeEditor(self)
-        self.editor.RegisterModifiedEvent(self.OnCodeModified)
-
-        self.btnSave = wx.Button(self, -1, "Save")
-        self.btnRestore = wx.Button(self, -1, "Restore")
-        self.btnSave.Enable(False)
-        self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
-        self.btnRestore.Bind(wx.EVT_BUTTON, self.OnRestore)
-
-        self.controlBox = wx.BoxSizer(wx.HORIZONTAL)
-        self.controlBox.Add(self.btnSave, 0, wx.RIGHT, 5)
-        self.controlBox.Add(self.btnRestore, 0)
-
-        self.box = wx.BoxSizer(wx.VERTICAL)
-        self.box.Add(self.controlBox, 0, wx.EXPAND)
-        self.box.Add(wx.StaticLine(self), 0, wx.EXPAND)
-        self.box.Add(self.editor, 1, wx.EXPAND)
-        
-        self.box.Fit(self)
-        self.SetSizer(self.box)
-        
-        self.sourceFile = None
-        
-        self.Bind(wx.EVT_MENU, self.OnSave, id=wx.ID_SAVE)
-        accel = wx.AcceleratorTable([wx.AcceleratorEntry(wx.ACCEL_CTRL, 83, wx.ID_SAVE)])
-        self.SetAcceleratorTable(accel)
-
-    # Loads from a file object
-    def LoadSourceFile(self, filename):
-        self.sourceFile = filename
-        if os.path.exists(filename):
-            self.LoadSource(file(filename).read())
-
-    def LoadSource(self, source):
-        self.editor.Clear()
-        self.editor.SetValue(source)
-        self.JumpToLine(0)
-        self.btnSave.Enable(False)
-
-    def JumpToLine(self, line, highlight=False):
-        self.editor.GotoLine(line)
-        self.editor.SetFocus()
-        if highlight:
-            self.editor.SelectLine(line)
-                    
-    def OnCodeModified(self, event):
-        self.btnSave.Enable(self.editor.IsModified())
-        # TODO : add callback
-        
-    def OnSave(self, event):
-        overwriteMsg = "You are about to overwrite that file\n" + \
-                       "Do you want to continue?"
-        dlg = wx.MessageDialog(self, overwriteMsg, "wxPython Demo",
-                               wx.YES_NO | wx.NO_DEFAULT| wx.ICON_EXCLAMATION)
-        result = dlg.ShowModal()
-        if result == wx.ID_NO:
-            return
-        dlg.Destroy()
-
-        source = self.editor.GetText().encode("utf-8")
-
-        f = file(self.sourceFile, "w")
-        f.write(source)
-        f.close()
-         
-        # TODO
-        #self.mainFrame.SetTreeModified(True)
-
-
-    def OnRestore(self, event):
-        self.LoadSourceFile(self.sourceFile)
-        self.btnSave.Enable(self.editor.IsModified())
--- a/plugger.py	Wed Jul 29 10:49:31 2009 +0200
+++ b/plugger.py	Wed Jul 29 15:17:10 2009 +0200
@@ -910,14 +910,6 @@
         # define name for IEC raw code file
         return os.path.join(self.PlugPath(), "raw_plc.st")
     
-    def _getPYTHONcodepath(self):
-        # define name for IEC raw code file
-        return os.path.join(self.PlugPath(), "runtime.py")
-
-    def _getWXGLADEpath(self):
-        # define name for IEC raw code file
-        return os.path.join(self.PlugPath(), "hmi.wxg")
-
     def GetLocations(self):
         locations = []
         filepath = os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h")
@@ -1073,15 +1065,6 @@
         else:
             return None
 
-    def launch_wxglade(self, options, wait=False):
-        from wxglade import __file__ as fileName
-        path = os.path.dirname(fileName)
-        glade = os.path.join(path, 'wxglade.py')
-        if wx.Platform == '__WXMSW__':
-            glade = "\"%s\""%glade
-        mode = {False:os.P_NOWAIT, True:os.P_WAIT}[wait]
-        os.spawnv(mode, sys.executable, ["\"%s\""%sys.executable] + [glade] + options)
-
     #######################################################################
     #
     #                C CODE GENERATION METHODS
@@ -1096,27 +1079,10 @@
         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
         """
 
-        res = ([(C_file_name, self.plcCFLAGS) 
+        return ([(C_file_name, self.plcCFLAGS) 
                 for C_file_name in self.PLCGeneratedCFiles ], 
                "", # no ldflags
                False) # do not expose retreive/publish calls
-        
-        pyfile=self._getPYTHONcodepath()
-        if os.path.exists(pyfile):
-            res += (("runtime.py", file(pyfile,"rb")),)
-        wxgfile=self._getWXGLADEpath()
-        if os.path.exists(wxgfile):
-            hmipyfile=os.path.join(self._getBuildPath(),"hmi.py")
-            if wx.Platform == '__WXMSW__':
-                wxgfile = "\"%s\""%wxgfile
-                _hmipyfile = "\"%s\""%hmipyfile
-            else:
-                _hmipyfile = hmipyfile
-            self.launch_wxglade(['-o', _hmipyfile, '-g', 'python', wxgfile], wait=True)
-            res += (("hmi.py", file(hmipyfile,"rb")),)
-
-        return res
-
     
     def ResetIECProgramsAndVariables(self):
         """
@@ -1211,23 +1177,6 @@
         
         return debug_code
         
-    def Generate_plc_python(self):
-        """
-        Generate trace/debug code out of PLC variable list
-        """
-        self.GetIECProgramsAndVariables()
-
-        python_eval_fb_list = []
-        for v in self._VariablesList :
-            if v["vartype"] == "FB" and v["type"] in ["PYTHON_EVAL","PYTHON_POLL"]:
-                python_eval_fb_list.append(v)
-        python_eval_fb_count = max(1, len(python_eval_fb_list))
-        
-        # prepare debug code
-        python_code = targets.code("plc_python") % {
-           "python_eval_fb_count": python_eval_fb_count}
-        return python_code
-        
     def Generate_plc_common_main(self):
         """
         Use plugins layout given in LocationCFilesAndCFLAGS to
@@ -1334,8 +1283,6 @@
         for generator, filename, name in [
            # debugger code
            (self.Generate_plc_debugger, "plc_debugger.c", "Debugger"),
-           # IEC<->python gateway code
-           (self.Generate_plc_python, "plc_python.c", "IEC-Python gateway"),
            # init/cleanup/retrieve/publish, run and align code
            (self.Generate_plc_common_main,"plc_common_main.c","Common runtime")]:
             try:
@@ -1407,32 +1354,6 @@
             
         new_dialog.Show()
 
-    def _editPYTHONcode(self):
-        from PythonSTC import PythonCodePanel
-        new_dialog = wx.Frame(self.AppFrame)
-        
-        PYTHON_viewer = PythonCodePanel(new_dialog, self.AppFrame)
-        #ST_viewer.Enable(False)
-        pyfile=self._getPYTHONcodepath()
-        PYTHON_viewer.LoadSourceFile(pyfile)
-            
-        new_dialog.Show()
-
-    def _editWXGLADE(self):
-        wxg_filename = self._getWXGLADEpath()
-        if not os.path.exists(wxg_filename):
-            open(wxg_filename,"w").write("""<?xml version="1.0"?>
-<application path="" name="" class="" option="0" language="python" top_window="frame_1" encoding="UTF-8" use_gettext="0" overwrite="0" use_new_namespace="1" for_version="2.8" is_template="0">
-    <object class="HMIFrame" name="frame_1" base="EditFrame">
-        <style>wxDEFAULT_FRAME_STYLE</style>
-        <title>frame_1</title>
-    </object>
-</application>
-""")
-        if wx.Platform == '__WXMSW__':
-            wxg_filename = "\"%s\""%wxg_filename
-        self.launch_wxglade([wxg_filename])
-        
     def _EditPLC(self):
         if self.PLCEditor is None:
             self.RefreshPluginsBlockLists()
@@ -1873,12 +1794,4 @@
          "name" : _("Raw IEC code"),
          "tooltip" : _("Edit raw IEC code added to code generated by PLCGenerator"),
          "method" : "_editIECrawcode"},
-        {"bitmap" : opjimg("editPYTHONcode"),
-         "name" : "Python code",
-         "tooltip" : "Write Python runtime code, for use with python_eval FBs",
-         "method" : "_editPYTHONcode"},
-        {"bitmap" : opjimg("editWXGLADE"),
-         "name" : "WXGLADE GUI",
-         "tooltip" : "Edit a WxWidgets GUI with WXGlade",
-         "method" : "_editWXGLADE"},
     ]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/python/PythonEditor.py	Wed Jul 29 15:17:10 2009 +0200
@@ -0,0 +1,594 @@
+import  wx, wx.grid
+import  wx.stc  as  stc
+import keyword
+
+if wx.Platform == '__WXMSW__':
+    faces = { 'times': 'Times New Roman',
+              'mono' : 'Courier New',
+              'helv' : 'Arial',
+              'other': 'Comic Sans MS',
+              'size' : 10,
+              'size2': 8,
+             }
+elif wx.Platform == '__WXMAC__':
+    faces = { 'times': 'Times New Roman',
+              'mono' : 'Monaco',
+              'helv' : 'Arial',
+              'other': 'Comic Sans MS',
+              'size' : 12,
+              'size2': 10,
+             }
+else:
+    faces = { 'times': 'Times',
+              'mono' : 'Courier',
+              'helv' : 'Helvetica',
+              'other': 'new century schoolbook',
+              'size' : 12,
+              'size2': 10,
+             }
+
+def AppendMenu(parent, help, id, kind, text):
+    if wx.VERSION >= (2, 6, 0):
+        parent.Append(help=help, id=id, kind=kind, text=text)
+    else:
+        parent.Append(helpString=help, id=id, kind=kind, item=text)
+
+
+[ID_PYTHONEDITOR,
+] = [wx.NewId() for _init_ctrls in range(1)]
+
+def GetCursorPos(old, new):
+    old_length = len(old)
+    new_length = len(new)
+    common_length = min(old_length, new_length)
+    i = 0
+    for i in xrange(common_length):
+        if old[i] != new[i]:
+            break
+    if old_length < new_length:
+        if common_length > 0 and old[i] != new[i]:
+            return i + new_length - old_length
+        else:
+            return i + new_length - old_length + 1
+    elif old_length > new_length or i < min(old_length, new_length) - 1:
+        if common_length > 0 and old[i] != new[i]:
+            return i
+        else:
+            return i + 1
+    else:
+        return None
+
+class PythonEditor(stc.StyledTextCtrl):
+
+    fold_symbols = 3
+    
+    def __init__(self, parent, window, controler):
+        stc.StyledTextCtrl.__init__(self, parent, ID_PYTHONEDITOR, wx.DefaultPosition, 
+                 wx.DefaultSize, 0)
+
+        self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
+        self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
+
+        self.SetLexer(stc.STC_LEX_PYTHON)
+        self.SetKeyWords(0, " ".join(keyword.kwlist))
+
+        self.SetProperty("fold", "1")
+        self.SetProperty("tab.timmy.whinge.level", "1")
+        self.SetMargins(0,0)
+
+        self.SetViewWhiteSpace(False)
+        #self.SetBufferedDraw(False)
+        #self.SetViewEOL(True)
+        #self.SetEOLMode(stc.STC_EOL_CRLF)
+        #self.SetUseAntiAliasing(True)
+        
+        self.SetEdgeMode(stc.STC_EDGE_BACKGROUND)
+        self.SetEdgeColumn(78)
+
+        # Set up the numbers in the margin for margin #1
+        self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER)
+        # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
+        self.SetMarginWidth(1, 40)
+
+        # Setup a margin to hold fold markers
+        self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
+        self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
+        self.SetMarginSensitive(2, True)
+        self.SetMarginWidth(2, 12)
+
+        if self.fold_symbols == 0:
+            # Arrow pointing right for contracted folders, arrow pointing down for expanded
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN,    stc.STC_MARK_ARROWDOWN, "black", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDER,        stc.STC_MARK_ARROW, "black", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB,     stc.STC_MARK_EMPTY, "black", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL,    stc.STC_MARK_EMPTY, "black", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND,     stc.STC_MARK_EMPTY,     "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY,     "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY,     "white", "black")
+            
+        elif self.fold_symbols == 1:
+            # Plus for contracted folders, minus for expanded
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN,    stc.STC_MARK_MINUS, "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDER,        stc.STC_MARK_PLUS,  "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB,     stc.STC_MARK_EMPTY, "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL,    stc.STC_MARK_EMPTY, "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND,     stc.STC_MARK_EMPTY, "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black")
+
+        elif self.fold_symbols == 2:
+            # Like a flattened tree control using circular headers and curved joins
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN,    stc.STC_MARK_CIRCLEMINUS,          "white", "#404040")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDER,        stc.STC_MARK_CIRCLEPLUS,           "white", "#404040")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB,     stc.STC_MARK_VLINE,                "white", "#404040")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL,    stc.STC_MARK_LCORNERCURVE,         "white", "#404040")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND,     stc.STC_MARK_CIRCLEPLUSCONNECTED,  "white", "#404040")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE,         "white", "#404040")
+
+        elif self.fold_symbols == 3:
+            # Like a flattened tree control using square headers
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN,    stc.STC_MARK_BOXMINUS,          "white", "#808080")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDER,        stc.STC_MARK_BOXPLUS,           "white", "#808080")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB,     stc.STC_MARK_VLINE,             "white", "#808080")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL,    stc.STC_MARK_LCORNER,           "white", "#808080")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND,     stc.STC_MARK_BOXPLUSCONNECTED,  "white", "#808080")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER,           "white", "#808080")
+
+
+        self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
+        self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
+        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
+
+        # Global default style
+        if wx.Platform == '__WXMSW__':
+            self.StyleSetSpec(stc.STC_STYLE_DEFAULT, 
+                              'fore:#000000,back:#FFFFFF,face:Courier New')
+        elif wx.Platform == '__WXMAC__':
+            # TODO: if this looks fine on Linux too, remove the Mac-specific case 
+            # and use this whenever OS != MSW.
+            self.StyleSetSpec(stc.STC_STYLE_DEFAULT, 
+                              'fore:#000000,back:#FFFFFF,face:Monaco')
+        else:
+            defsize = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT).GetPointSize()
+            self.StyleSetSpec(stc.STC_STYLE_DEFAULT, 
+                              'fore:#000000,back:#FFFFFF,face:Courier,size:%d'%defsize)
+
+        # Clear styles and revert to default.
+        self.StyleClearAll()
+
+        # Following style specs only indicate differences from default.
+        # The rest remains unchanged.
+
+        # Line numbers in margin
+        self.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2')    
+        # Highlighted brace
+        self.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00')
+        # Unmatched brace
+        self.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000')
+        # Indentation guide
+        self.StyleSetSpec(wx.stc.STC_STYLE_INDENTGUIDE, "fore:#CDCDCD")
+
+        # Python styles
+        self.StyleSetSpec(wx.stc.STC_P_DEFAULT, 'fore:#000000')
+        # Comments
+        self.StyleSetSpec(wx.stc.STC_P_COMMENTLINE,  'fore:#008000,back:#F0FFF0')
+        self.StyleSetSpec(wx.stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0')
+        # Numbers
+        self.StyleSetSpec(wx.stc.STC_P_NUMBER, 'fore:#008080')
+        # Strings and characters
+        self.StyleSetSpec(wx.stc.STC_P_STRING, 'fore:#800080')
+        self.StyleSetSpec(wx.stc.STC_P_CHARACTER, 'fore:#800080')
+        # Keywords
+        self.StyleSetSpec(wx.stc.STC_P_WORD, 'fore:#000080,bold')
+        # Triple quotes
+        self.StyleSetSpec(wx.stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA')
+        self.StyleSetSpec(wx.stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA')
+        # Class names
+        self.StyleSetSpec(wx.stc.STC_P_CLASSNAME, 'fore:#0000FF,bold')
+        # Function names
+        self.StyleSetSpec(wx.stc.STC_P_DEFNAME, 'fore:#008080,bold')
+        # Operators
+        self.StyleSetSpec(wx.stc.STC_P_OPERATOR, 'fore:#800000,bold')
+        # Identifiers. I leave this as not bold because everything seems
+        # to be an identifier if it doesn't match the above criterae
+        self.StyleSetSpec(wx.stc.STC_P_IDENTIFIER, 'fore:#000000')
+
+        # Caret color
+        self.SetCaretForeground("BLUE")
+        # Selection background
+        self.SetSelBackground(1, '#66CCFF')
+
+        self.SetSelBackground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
+        self.SetSelForeground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))
+        
+        # register some images for use in the AutoComplete box.
+        #self.RegisterImage(1, images.getSmilesBitmap())
+        self.RegisterImage(1, 
+            wx.ArtProvider.GetBitmap(wx.ART_DELETE, size=(16,16)))
+        self.RegisterImage(2, 
+            wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16)))
+        self.RegisterImage(3, 
+            wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16)))
+
+        # Indentation and tab stuff
+        self.SetIndent(4)               # Proscribed indent size for wx
+        self.SetIndentationGuides(True) # Show indent guides
+        self.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
+        self.SetTabIndents(True)        # Tab key indents
+        self.SetTabWidth(4)             # Proscribed tab size for wx
+        self.SetUseTabs(False)          # Use spaces rather than tabs, or
+                                        # TabTimmy will complain!    
+        # White space
+        self.SetViewWhiteSpace(False)   # Don't view white space
+
+        # EOL: Since we are loading/saving ourselves, and the
+        # strings will always have \n's in them, set the STC to
+        # edit them that way.            
+        self.SetEOLMode(wx.stc.STC_EOL_LF)
+        self.SetViewEOL(False)
+        
+        # No right-edge mode indicator
+        self.SetEdgeMode(stc.STC_EDGE_NONE)
+
+        self.Controler = controler
+        self.ParentWindow = window
+        
+        self.DisableEvents = True
+        self.CurrentAction = None
+        
+        self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE)
+
+        self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_PYTHONEDITOR)
+        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
+        self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_PYTHONEDITOR)
+    
+    def OnModification(self, event):
+        if not self.DisableEvents:
+            mod_type = event.GetModificationType()
+            if not (mod_type&wx.stc.STC_PERFORMED_UNDO or mod_type&wx.stc.STC_PERFORMED_REDO):
+                if mod_type&wx.stc.STC_MOD_BEFOREINSERT:
+                    if self.CurrentAction == None:
+                        self.StartBuffering()
+                    elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1:
+                        self.Controler.EndBuffering()
+                        self.StartBuffering()
+                    self.CurrentAction = ("Add", event.GetPosition())
+                elif mod_type&wx.stc.STC_MOD_BEFOREDELETE:
+                    if self.CurrentAction == None:
+                        self.StartBuffering()
+                    elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1:
+                        self.Controler.EndBuffering()
+                        self.StartBuffering()
+                    self.CurrentAction = ("Delete", event.GetPosition())
+        event.Skip()
+    
+    def OnDoDrop(self, event):
+        self.ResetBuffer()
+        wx.CallAfter(self.RefreshModel)
+        event.Skip()
+
+    def IsViewing(self, name):
+        return self.Name == name
+
+    # Buffer the last model state
+    def RefreshBuffer(self):
+        self.Controler.BufferPython()
+        if self.ParentWindow:
+            self.ParentWindow.RefreshTitle()
+            self.ParentWindow.RefreshEditMenu()
+    
+    def StartBuffering(self):
+        self.Controler.StartBuffering()
+        if self.ParentWindow:
+            self.ParentWindow.RefreshTitle()
+            self.ParentWindow.RefreshEditMenu()
+    
+    def ResetBuffer(self):
+        if self.CurrentAction != None:
+            self.Controler.EndBuffering()
+            self.CurrentAction = None
+
+    def RefreshView(self):
+        self.ResetBuffer()
+        self.DisableEvents = True
+        old_cursor_pos = self.GetCurrentPos()
+        old_text = self.GetText()
+        new_text = self.Controler.GetPythonCode()
+        self.SetText(new_text)
+        new_cursor_pos = GetCursorPos(old_text, new_text)
+        if new_cursor_pos != None:
+            self.GotoPos(new_cursor_pos)
+        else:
+            self.GotoPos(old_cursor_pos)
+        self.ScrollToColumn(0)
+        self.EmptyUndoBuffer()
+        self.DisableEvents = False
+        
+        self.Colourise(0, -1)
+
+    def RefreshModel(self):
+        self.Controler.SetPythonCode(self.GetText())
+
+    def OnKeyPressed(self, event):
+        if self.CallTipActive():
+            self.CallTipCancel()
+        key = event.GetKeyCode()
+
+        if key == 32 and event.ControlDown():
+            pos = self.GetCurrentPos()
+
+            # Tips
+            if event.ShiftDown():
+                pass
+##                self.CallTipSetBackground("yellow")
+##                self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n'
+##                                 'show some suff, maybe parameters..\n\n'
+##                                 'fubar(param1, param2)')
+            # Code completion
+            else:
+                self.AutoCompSetIgnoreCase(False)  # so this needs to match
+
+                # Images are specified with a appended "?type"
+                self.AutoCompShow(0, " ".join([word + "?1" for word in keyword.kwlist]))
+        else:
+            wx.CallAfter(self.RefreshModel)
+            event.Skip()
+
+    def OnKillFocus(self, event):
+        self.AutoCompCancel()
+        event.Skip()
+
+    def OnUpdateUI(self, evt):
+        # check for matching braces
+        braceAtCaret = -1
+        braceOpposite = -1
+        charBefore = None
+        caretPos = self.GetCurrentPos()
+
+        if caretPos > 0:
+            charBefore = self.GetCharAt(caretPos - 1)
+            styleBefore = self.GetStyleAt(caretPos - 1)
+
+        # check before
+        if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
+            braceAtCaret = caretPos - 1
+
+        # check after
+        if braceAtCaret < 0:
+            charAfter = self.GetCharAt(caretPos)
+            styleAfter = self.GetStyleAt(caretPos)
+
+            if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
+                braceAtCaret = caretPos
+
+        if braceAtCaret >= 0:
+            braceOpposite = self.BraceMatch(braceAtCaret)
+
+        if braceAtCaret != -1  and braceOpposite == -1:
+            self.BraceBadLight(braceAtCaret)
+        else:
+            self.BraceHighlight(braceAtCaret, braceOpposite)
+            #pt = self.PointFromPosition(braceOpposite)
+            #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
+            #print pt
+            #self.Refresh(False)
+
+
+    def OnMarginClick(self, evt):
+        # fold and unfold as needed
+        if evt.GetMargin() == 2:
+            if evt.GetShift() and evt.GetControl():
+                self.FoldAll()
+            else:
+                lineClicked = self.LineFromPosition(evt.GetPosition())
+
+                if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
+                    if evt.GetShift():
+                        self.SetFoldExpanded(lineClicked, True)
+                        self.Expand(lineClicked, True, True, 1)
+                    elif evt.GetControl():
+                        if self.GetFoldExpanded(lineClicked):
+                            self.SetFoldExpanded(lineClicked, False)
+                            self.Expand(lineClicked, False, True, 0)
+                        else:
+                            self.SetFoldExpanded(lineClicked, True)
+                            self.Expand(lineClicked, True, True, 100)
+                    else:
+                        self.ToggleFold(lineClicked)
+
+
+    def FoldAll(self):
+        lineCount = self.GetLineCount()
+        expanding = True
+
+        # find out if we are folding or unfolding
+        for lineNum in range(lineCount):
+            if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
+                expanding = not self.GetFoldExpanded(lineNum)
+                break
+
+        lineNum = 0
+
+        while lineNum < lineCount:
+            level = self.GetFoldLevel(lineNum)
+            if level & stc.STC_FOLDLEVELHEADERFLAG and \
+               (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
+
+                if expanding:
+                    self.SetFoldExpanded(lineNum, True)
+                    lineNum = self.Expand(lineNum, True)
+                    lineNum = lineNum - 1
+                else:
+                    lastChild = self.GetLastChild(lineNum, -1)
+                    self.SetFoldExpanded(lineNum, False)
+
+                    if lastChild > lineNum:
+                        self.HideLines(lineNum+1, lastChild)
+
+            lineNum = lineNum + 1
+
+
+
+    def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
+        lastChild = self.GetLastChild(line, level)
+        line = line + 1
+
+        while line <= lastChild:
+            if force:
+                if visLevels > 0:
+                    self.ShowLines(line, line)
+                else:
+                    self.HideLines(line, line)
+            else:
+                if doExpand:
+                    self.ShowLines(line, line)
+
+            if level == -1:
+                level = self.GetFoldLevel(line)
+
+            if level & stc.STC_FOLDLEVELHEADERFLAG:
+                if force:
+                    if visLevels > 1:
+                        self.SetFoldExpanded(line, True)
+                    else:
+                        self.SetFoldExpanded(line, False)
+
+                    line = self.Expand(line, doExpand, force, visLevels-1)
+
+                else:
+                    if doExpand and self.GetFoldExpanded(line):
+                        line = self.Expand(line, True, force, visLevels-1)
+                    else:
+                        line = self.Expand(line, False, force, visLevels-1)
+            else:
+                line = line + 1
+
+        return line
+   
+
+#-------------------------------------------------------------------------------
+#                          PythonEditor Main Frame Class
+#-------------------------------------------------------------------------------
+
+
+[ID_PYTHONEDITORFRAME, 
+] = [wx.NewId() for _init_ctrls in range(1)]
+
+class PythonEditorFrame(wx.Frame):
+    
+    if wx.VERSION < (2, 6, 0):
+        def Bind(self, event, function, id = None):
+            if id is not None:
+                event(self, id, function)
+            else:
+                event(self, function)
+    
+    def _init_coll_EditMenu_Items(self, parent):
+        AppendMenu(parent, help='', id=wx.ID_REFRESH,
+              kind=wx.ITEM_NORMAL, text=u'Refresh\tCTRL+R')
+        AppendMenu(parent, help='', id=wx.ID_UNDO,
+              kind=wx.ITEM_NORMAL, text=u'Undo\tCTRL+Z')
+        AppendMenu(parent, help='', id=wx.ID_REDO,
+              kind=wx.ITEM_NORMAL, text=u'Redo\tCTRL+Y')
+        self.Bind(wx.EVT_MENU, self.OnRefreshMenu, id=wx.ID_REFRESH)
+        self.Bind(wx.EVT_MENU, self.OnUndoMenu, id=wx.ID_UNDO)
+        self.Bind(wx.EVT_MENU, self.OnRedoMenu, id=wx.ID_REDO)
+    
+    def _init_coll_MenuBar_Menus(self, parent):
+        parent.Append(menu=self.EditMenu, title=u'&Edit')
+    
+    def _init_utils(self):
+        self.MenuBar = wx.MenuBar()
+
+        self.EditMenu = wx.Menu(title='')
+        
+        self._init_coll_MenuBar_Menus(self.MenuBar)
+        self._init_coll_EditMenu_Items(self.EditMenu)
+        
+    def _init_ctrls(self, prnt):
+        wx.Frame.__init__(self, id=ID_PYTHONEDITORFRAME, name=u'PythonEditor',
+              parent=prnt, pos=wx.DefaultPosition, size=wx.Size(800, 650),
+              style=wx.DEFAULT_FRAME_STYLE, title=u'PythonEditor')
+        self._init_utils()
+        self.SetClientSize(wx.Size(1000, 600))
+        self.SetMenuBar(self.MenuBar)
+        self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
+        
+        self.Bind(wx.EVT_MENU, self.OnSaveMenu, id=wx.ID_SAVE)
+        accel = wx.AcceleratorTable([wx.AcceleratorEntry(wx.ACCEL_CTRL, 83, wx.ID_SAVE)])
+        self.SetAcceleratorTable(accel)
+        
+        if wx.VERSION >= (2, 8, 0):
+            self.AUIManager = wx.aui.AuiManager(self)
+            self.AUIManager.SetDockSizeConstraint(0.5, 0.5)
+        
+        self.PythonEdited = PythonEditor(self, self, self.Controler)
+        if wx.VERSION < (2, 8, 0):
+            self.MainSizer = wx.BoxSizer(wx.VERTICAL)
+            self.MainSizer.AddWindow(self.PythonEdited, 0, border=0, flag=wx.GROW)
+            self.SetSizer(self.MainSizer)
+        else:
+            self.AUIManager.AddPane(self.PythonEdited, wx.aui.AuiPaneInfo().CentrePane())
+            
+        self.StatusBar = wx.StatusBar( name='HelpBar',
+              parent=self, style=wx.ST_SIZEGRIP)
+        self.SetStatusBar(self.StatusBar)
+        
+        if wx.VERSION >= (2, 8, 0):
+            self.AUIManager.Update()
+    
+    def __init__(self, parent, controler):
+        self.Controler = controler
+        
+        self._init_ctrls(parent)
+        
+        self.PythonEdited.RefreshView()
+        self.RefreshTitle()
+        self.RefreshEditMenu()
+
+    def OnCloseFrame(self, event):
+        if wx.VERSION >= (2, 8, 0):
+            self.AUIManager.UnInit()
+        if getattr(self, "_onclose", None) is not None:
+            self._onclose()
+        event.Skip()
+
+    def OnSaveMenu(self, event):
+        if getattr(self, "_onsave", None) != None:
+            self._onsave()
+        self.RefreshTitle()
+        self.RefreshEditMenu()
+        event.Skip()
+
+    def RefreshTitle(self):
+        self.SetTitle("PythonEditor - %s"%self.Controler.GetFilename())
+        
+#-------------------------------------------------------------------------------
+#                          Edit Project Menu Functions
+#-------------------------------------------------------------------------------
+
+    def RefreshEditMenu(self):
+        undo, redo = self.Controler.GetBufferState()
+        self.EditMenu.Enable(wx.ID_UNDO, undo)
+        self.EditMenu.Enable(wx.ID_REDO, redo)
+
+    def OnRefreshMenu(self, event):
+        self.PythonEdited.RefreshView()
+        event.Skip()
+
+    def OnUndoMenu(self, event):
+        self.Controler.LoadPrevious()
+        self.PythonEdited.RefreshView()
+        self.RefreshTitle()
+        self.RefreshEditMenu()
+        event.Skip()
+    
+    def OnRedoMenu(self, event):
+        self.Controler.LoadNext()
+        self.PythonEdited.RefreshView()
+        self.RefreshTitle()
+        self.RefreshEditMenu()
+        event.Skip()
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/python/README	Wed Jul 29 15:17:10 2009 +0200
@@ -0,0 +1,1 @@
+Asynchronous
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/python/__init__.py	Wed Jul 29 15:17:10 2009 +0200
@@ -0,0 +1,1 @@
+from python import *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/python/modules/__init__.py	Wed Jul 29 15:17:10 2009 +0200
@@ -0,0 +1,13 @@
+from os import listdir, path
+
+_base_path = path.split(__file__)[0]
+
+__all__ = [name for name in listdir(_base_path) if path.isdir(path.join(_base_path, name)) and name.upper() != "CVS" or name.endswith(".py") and not name.startswith("__")]
+
+helps = []
+for name in __all__:
+    helpfilename = path.join(_base_path, name, "README")
+    if path.isfile(helpfilename):
+        helps.append(open(helpfilename).readline().strip())
+    else:
+        helps.append(name)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/python/plc_python.c	Wed Jul 29 15:17:10 2009 +0200
@@ -0,0 +1,214 @@
+/*
+ * Python Asynchronous execution code
+ *
+ * PLC put python commands in a fifo, respecting execution order
+ * with the help of C pragmas inserted in python_eval FB code
+ *
+ * Buffer content is read asynchronously, (from non real time part),
+ * commands are executed and result stored for later use by PLC.
+ *
+ * In this implementation, fifo is a list of pointer to python_eval
+ * function blocks structures. Some local variables have been added in
+ * python_eval interface. We use those local variables as buffer and state
+ * flags.
+ *
+ * */
+
+#include "iec_types_all.h"
+#include "POUS.h"
+#include <string.h>
+
+/* The fifo (fixed size, as number of FB is fixed) */
+static PYTHON_EVAL* EvalFBs[%(python_eval_fb_count)d];
+/* Producer and consumer cursors */
+static int Current_PLC_EvalFB;
+static int Current_Python_EvalFB;
+
+/* A global IEC-Python gateway state, for use inside python_eval FBs*/
+static int PythonState;
+#define PYTHON_LOCKED_BY_PYTHON 0
+#define PYTHON_LOCKED_BY_PLC 1
+#define PYTHON_MUSTWAKEUP 2
+#define PYTHON_FINISHED 4
+
+/* Each python_eval FunctionBlock have it own state */
+#define PYTHON_FB_FREE 0
+#define PYTHON_FB_REQUESTED 1
+#define PYTHON_FB_PROCESSING 2
+#define PYTHON_FB_ANSWERED 3
+
+int WaitPythonCommands(void);
+void UnBlockPythonCommands(void);
+int TryLockPython(void);
+void UnLockPython(void);
+void LockPython(void);
+
+int __init_%(location)s()
+{
+	int i;
+	/* Initialize cursors */
+	Current_Python_EvalFB = 0;
+	Current_PLC_EvalFB = 0;
+	PythonState = PYTHON_LOCKED_BY_PYTHON;
+	for(i = 0; i < %(python_eval_fb_count)d; i++)
+		EvalFBs[i] = NULL;
+  return 0;
+}
+
+void __cleanup_%(location)s()
+{
+	PythonState = PYTHON_FINISHED;
+	UnBlockPythonCommands();
+}
+
+void __retrieve_%(location)s()
+{
+	/* Check Python thread is not being
+	 * modifying internal python_eval data */
+	PythonState = TryLockPython() ?
+	                PYTHON_LOCKED_BY_PLC :
+	                PYTHON_LOCKED_BY_PYTHON;
+	/* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON
+	 * and python_eval will no do anything */
+}
+
+void __publish_%(location)s()
+{
+	if(PythonState & PYTHON_LOCKED_BY_PLC){
+		/* If runnig PLC did push something in the fifo*/
+		if(PythonState & PYTHON_MUSTWAKEUP){
+			/* WakeUp python thread */
+			UnBlockPythonCommands();
+		}
+		UnLockPython();
+	}
+}
+/**
+ * Called by the PLC, each time a python_eval
+ * FB instance is executed
+ */
+void __PythonEvalFB(int poll, PYTHON_EVAL* data__)
+{
+	/* detect rising edge on TRIG to trigger evaluation */
+	if(((data__->TRIG && !data__->TRIGM1) ||
+	   /* polling is equivalent to trig on value rather than on rising edge*/
+	    (poll && data__->TRIG )) &&
+	    /* trig only if not already trigged */
+	   data__->TRIGGED == 0){
+		/* mark as trigged */
+		data__->TRIGGED = 1;
+		/* make a safe copy of the code */
+		data__->PREBUFFER = data__->CODE;
+	}
+	/* retain value for next rising edge detection */
+	data__->TRIGM1 = data__->TRIG;
+
+	/* python thread is not in ? */
+	if( PythonState & PYTHON_LOCKED_BY_PLC){
+		/* if some answer are waiting, publish*/
+		if(data__->STATE == PYTHON_FB_ANSWERED){
+			/* Copy buffer content into result*/
+			data__->RESULT = data__->BUFFER;
+			/* signal result presece to PLC*/
+			data__->ACK = 1;
+			/* Mark as free */
+			data__->STATE = PYTHON_FB_FREE;
+			/* mark as not trigged */
+			if(!poll)
+				data__->TRIGGED = 0;
+			/*printf("__PythonEvalFB pop %%d - %%*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/
+		}else if(poll){
+			/* when in polling, no answer == ack down */
+			data__->ACK = 0;
+		}
+		/* got the order to act ?*/
+		if(data__->TRIGGED == 1 &&
+		   /* and not already being processed */
+		   data__->STATE == PYTHON_FB_FREE)
+		{
+			/* Enter the block in the fifo
+			/* Don't have to check if fifo cell is free
+			 * as fifo size == FB count, and a FB cannot
+			 * be requested twice */
+			EvalFBs[Current_PLC_EvalFB] = data__;
+			/* copy into BUFFER local*/
+			data__->BUFFER = data__->PREBUFFER;
+			/* Set ACK pin to low so that we can set a rising edge on result */
+			if(!poll){
+				/* when not polling, a new answer imply reseting ack*/
+				data__->ACK = 0;
+			}else{
+				/* when in polling, acting reset trigger */
+				data__->TRIGGED = 0;
+			}
+			/* Mark FB busy */
+			data__->STATE = PYTHON_FB_REQUESTED;
+			/* Have to wakeup python thread in case he was asleep */
+			PythonState |= PYTHON_MUSTWAKEUP;
+			/*printf("__PythonEvalFB push %%d - %%*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/
+			/* Get a new line */
+			Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) %% %(python_eval_fb_count)d;
+		}
+	}
+}
+
+char* PythonIterator(char* result)
+{
+	char* next_command;
+	PYTHON_EVAL* data__;
+	//printf("PythonIterator result %%s\n", result);
+	/* take python mutex to prevent changing PLC data while PLC running */
+	LockPython();
+	/* Get current FB */
+	data__ = EvalFBs[Current_Python_EvalFB];
+	if(data__ && /* may be null at first run */
+	   data__->STATE == PYTHON_FB_PROCESSING){ /* some answer awaited*/
+	   	/* If result not None */
+	   	if(result){
+			/* Get results len */
+			data__->BUFFER.len = strlen(result);
+			/* prevent results overrun */
+			if(data__->BUFFER.len > STR_MAX_LEN)
+			{
+				data__->BUFFER.len = STR_MAX_LEN;
+				/* TODO : signal error */
+			}
+			/* Copy results to buffer */
+			strncpy(data__->BUFFER.body, result, data__->BUFFER.len);
+	   	}else{
+	   		data__->BUFFER.len = 0;
+	   	}
+		/* remove block from fifo*/
+		EvalFBs[Current_Python_EvalFB] = NULL;
+		/* Mark block as answered */
+		data__->STATE = PYTHON_FB_ANSWERED;
+		/* Get a new line */
+		Current_Python_EvalFB = (Current_Python_EvalFB + 1) %% %(python_eval_fb_count)d;
+		//printf("PythonIterator ++ Current_Python_EvalFB %%d\n", Current_Python_EvalFB);
+	}
+	/* while next slot is empty */
+	while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) ||
+	 	  /* or doesn't contain command */
+	      data__->STATE != PYTHON_FB_REQUESTED)
+	{
+		UnLockPython();
+		/* wait next FB to eval */
+		//printf("PythonIterator wait\n");
+		if(WaitPythonCommands()) return NULL;
+		/*emergency exit*/
+		if(PythonState & PYTHON_FINISHED) return NULL;
+		LockPython();
+	}
+	/* Mark block as processing */
+	data__->STATE = PYTHON_FB_PROCESSING;
+	//printf("PythonIterator\n");
+	/* make BUFFER a null terminated string */
+	data__->BUFFER.body[data__->BUFFER.len] = 0;
+	/* next command is BUFFER */
+	next_command = data__->BUFFER.body;
+	/* free python mutex */
+	UnLockPython();
+	/* return the next command to eval */
+	return next_command;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/python/pous.xml	Wed Jul 29 15:17:10 2009 +0200
@@ -0,0 +1,457 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://www.plcopen.org/xml/tc6.xsd"
+         xmlns:xhtml="http://www.w3.org/1999/xhtml"
+         xsi:schemaLocation="http://www.plcopen.org/xml/tc6.xsd">
+  <fileHeader companyName="LOLITECH"
+              productName="Beremiz"
+              productVersion="0.0"
+              creationDateTime="2008-12-14T16:53:26"/>
+  <contentHeader name="Beremiz non-standard POUs library"
+                 modificationDateTime="2008-12-23T22:35:46">
+    <coordinateInfo>
+      <fbd>
+        <scaling x="0" y="0"/>
+      </fbd>
+      <ld>
+        <scaling x="0" y="0"/>
+      </ld>
+      <sfc>
+        <scaling x="0" y="0"/>
+      </sfc>
+    </coordinateInfo>
+  </contentHeader>
+  <types>
+    <dataTypes/>
+    <pous>
+      <pou name="python_eval" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="TRIG">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CODE">
+              <type>
+                <string/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="ACK">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="RESULT">
+              <type>
+                <string/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="STATE">
+              <type>
+                <DWORD/>
+              </type>
+            </variable>
+            <variable name="BUFFER">
+              <type>
+                <string/>
+              </type>
+            </variable>
+            <variable name="PREBUFFER">
+              <type>
+                <string/>
+              </type>
+            </variable>
+            <variable name="TRIGM1">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="TRIGGED">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+<![CDATA[{extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);}]]>
+          </ST>
+        </body>
+      </pou>
+      <pou name="python_poll" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="TRIG">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CODE">
+              <type>
+                <string/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="ACK">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="RESULT">
+              <type>
+                <string/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="STATE">
+              <type>
+                <DWORD/>
+              </type>
+            </variable>
+            <variable name="BUFFER">
+              <type>
+                <string/>
+              </type>
+            </variable>
+            <variable name="PREBUFFER">
+              <type>
+                <string/>
+              </type>
+            </variable>
+            <variable name="TRIGM1">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="TRIGGED">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <ST>
+<![CDATA[{extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);}]]>
+          </ST>
+        </body>
+      </pou>
+    <pou name="python_gear" pouType="functionBlock">
+        <interface>
+          <inputVars>
+            <variable name="N">
+              <type>
+                <USINT/>
+              </type>
+            </variable>
+            <variable name="TRIG">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="CODE">
+              <type>
+                <string/>
+              </type>
+            </variable>
+          </inputVars>
+          <outputVars>
+            <variable name="ACK">
+              <type>
+                <BOOL/>
+              </type>
+            </variable>
+            <variable name="RESULT">
+              <type>
+                <string/>
+              </type>
+            </variable>
+          </outputVars>
+          <localVars>
+            <variable name="py_eval">
+              <type>
+                <derived name="python_eval"/>
+              </type>
+            </variable>
+            <variable name="COUNTER">
+              <type>
+                <USINT/>
+              </type>
+            </variable>
+          </localVars>
+        </interface>
+        <body>
+          <FBD>
+            <block localId="1" width="125" height="110" typeName="python_eval" instanceName="py_eval">
+              <position x="525" y="580"/>
+              <inputVariables>
+                <variable formalParameter="TRIG">
+                  <connectionPointIn>
+                    <relPosition x="0" y="40"/>
+                    <connection refLocalId="7" formalParameter="OUT">
+                      <position x="525" y="620"/>
+                      <position x="495" y="620"/>
+                      <position x="495" y="575"/>
+                      <position x="465" y="575"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+                <variable formalParameter="CODE">
+                  <connectionPointIn>
+                    <relPosition x="0" y="85"/>
+                    <connection refLocalId="4">
+                      <position x="525" y="665"/>
+                      <position x="370" y="665"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables>
+                <variable formalParameter="ACK">
+                  <connectionPointOut>
+                    <relPosition x="125" y="40"/>
+                  </connectionPointOut>
+                </variable>
+                <variable formalParameter="RESULT">
+                  <connectionPointOut>
+                    <relPosition x="125" y="85"/>
+                  </connectionPointOut>
+                </variable>
+              </outputVariables>
+            </block>
+            <inVariable localId="2" height="35" width="25">
+              <position x="435" y="270"/>
+              <connectionPointOut>
+                <relPosition x="25" y="15"/>
+              </connectionPointOut>
+              <expression>N</expression>
+            </inVariable>
+            <inVariable localId="3" height="35" width="55">
+              <position x="275" y="585"/>
+              <connectionPointOut>
+                <relPosition x="55" y="15"/>
+              </connectionPointOut>
+              <expression>TRIG</expression>
+            </inVariable>
+            <inVariable localId="4" height="35" width="55">
+              <position x="315" y="650"/>
+              <connectionPointOut>
+                <relPosition x="55" y="15"/>
+              </connectionPointOut>
+              <expression>CODE</expression>
+            </inVariable>
+            <outVariable localId="5" height="35" width="45">
+              <position x="740" y="605"/>
+              <connectionPointIn>
+                <relPosition x="0" y="15"/>
+                <connection refLocalId="1" formalParameter="ACK">
+                  <position x="740" y="620"/>
+                  <position x="650" y="620"/>
+                </connection>
+              </connectionPointIn>
+              <expression>ACK</expression>
+            </outVariable>
+            <outVariable localId="6" height="35" width="75">
+              <position x="740" y="650"/>
+              <connectionPointIn>
+                <relPosition x="0" y="15"/>
+                <connection refLocalId="1" formalParameter="RESULT">
+                  <position x="740" y="665"/>
+                  <position x="650" y="665"/>
+                </connection>
+              </connectionPointIn>
+              <expression>RESULT</expression>
+            </outVariable>
+            <block localId="7" width="80" height="65" typeName="AND">
+              <position x="385" y="545"/>
+              <inputVariables>
+                <variable formalParameter="IN1">
+                  <connectionPointIn>
+                    <relPosition x="0" y="30"/>
+                    <connection refLocalId="13" formalParameter="OUT">
+                      <position x="385" y="575"/>
+                      <position x="335" y="575"/>
+                      <position x="335" y="455"/>
+                      <position x="625" y="455"/>
+                      <position x="625" y="285"/>
+                      <position x="615" y="285"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+                <variable formalParameter="IN2">
+                  <connectionPointIn>
+                    <relPosition x="0" y="55"/>
+                    <connection refLocalId="3">
+                      <position x="385" y="600"/>
+                      <position x="330" y="600"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables>
+                <variable formalParameter="OUT">
+                  <connectionPointOut>
+                    <relPosition x="80" y="30"/>
+                  </connectionPointOut>
+                </variable>
+              </outputVariables>
+            </block>
+            <inVariable localId="9" height="35" width="85">
+              <position x="240" y="330"/>
+              <connectionPointOut>
+                <relPosition x="85" y="15"/>
+              </connectionPointOut>
+              <expression>COUNTER</expression>
+            </inVariable>
+            <block localId="10" width="80" height="65" typeName="ADD">
+              <position x="380" y="330"/>
+              <inputVariables>
+                <variable formalParameter="IN1">
+                  <connectionPointIn>
+                    <relPosition x="0" y="30"/>
+                    <connection refLocalId="9">
+                      <position x="380" y="360"/>
+                      <position x="352" y="360"/>
+                      <position x="352" y="345"/>
+                      <position x="325" y="345"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+                <variable formalParameter="IN2">
+                  <connectionPointIn>
+                    <relPosition x="0" y="55"/>
+                    <connection refLocalId="11">
+                      <position x="380" y="385"/>
+                      <position x="325" y="385"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables>
+                <variable formalParameter="OUT">
+                  <connectionPointOut>
+                    <relPosition x="80" y="30"/>
+                  </connectionPointOut>
+                </variable>
+              </outputVariables>
+            </block>
+            <inVariable localId="11" height="35" width="85">
+              <position x="240" y="370"/>
+              <connectionPointOut>
+                <relPosition x="85" y="15"/>
+              </connectionPointOut>
+              <expression>USINT#1</expression>
+            </inVariable>
+            <block localId="13" width="80" height="65" typeName="EQ">
+              <position x="535" y="255"/>
+              <inputVariables>
+                <variable formalParameter="IN1">
+                  <connectionPointIn>
+                    <relPosition x="0" y="30"/>
+                    <connection refLocalId="2">
+                      <position x="535" y="285"/>
+                      <position x="460" y="285"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+                <variable formalParameter="IN2">
+                  <connectionPointIn>
+                    <relPosition x="0" y="55"/>
+                    <connection refLocalId="10" formalParameter="OUT">
+                      <position x="535" y="310"/>
+                      <position x="497" y="310"/>
+                      <position x="497" y="360"/>
+                      <position x="460" y="360"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables>
+                <variable formalParameter="OUT">
+                  <connectionPointOut>
+                    <relPosition x="80" y="30"/>
+                  </connectionPointOut>
+                </variable>
+              </outputVariables>
+            </block>
+            <block localId="15" width="80" height="135" typeName="SEL">
+              <position x="785" y="245"/>
+              <inputVariables>
+                <variable formalParameter="G">
+                  <connectionPointIn>
+                    <relPosition x="0" y="40"/>
+                    <connection refLocalId="13" formalParameter="OUT">
+                      <position x="785" y="285"/>
+                      <position x="615" y="285"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+                <variable formalParameter="IN0">
+                  <connectionPointIn>
+                    <relPosition x="0" y="75"/>
+                    <connection refLocalId="10" formalParameter="OUT">
+                      <position x="785" y="320"/>
+                      <position x="650" y="320"/>
+                      <position x="650" y="360"/>
+                      <position x="460" y="360"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+                <variable formalParameter="IN1">
+                  <connectionPointIn>
+                    <relPosition x="0" y="115"/>
+                    <connection refLocalId="16">
+                      <position x="785" y="360"/>
+                      <position x="760" y="360"/>
+                    </connection>
+                  </connectionPointIn>
+                </variable>
+              </inputVariables>
+              <inOutVariables/>
+              <outputVariables>
+                <variable formalParameter="OUT">
+                  <connectionPointOut>
+                    <relPosition x="80" y="40"/>
+                  </connectionPointOut>
+                </variable>
+              </outputVariables>
+            </block>
+            <inVariable localId="16" height="35" width="85">
+              <position x="675" y="345"/>
+              <connectionPointOut>
+                <relPosition x="85" y="15"/>
+              </connectionPointOut>
+              <expression>USINT#0</expression>
+            </inVariable>
+            <outVariable localId="17" height="35" width="85">
+              <position x="905" y="270"/>
+              <connectionPointIn>
+                <relPosition x="0" y="15"/>
+                <connection refLocalId="15" formalParameter="OUT">
+                  <position x="905" y="285"/>
+                  <position x="865" y="285"/>
+                </connection>
+              </connectionPointIn>
+              <expression>COUNTER</expression>
+            </outVariable>
+          </FBD>
+        </body>
+      </pou>
+    </pous>
+  </types>
+  <instances>
+    <configurations/>
+  </instances>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/python/python.py	Wed Jul 29 15:17:10 2009 +0200
@@ -0,0 +1,280 @@
+import wx
+import os
+import modules
+from plugger import PlugTemplate, opjimg
+from PythonEditor import PythonEditorFrame
+
+from xml.dom import minidom
+from xmlclass import *
+import cPickle
+
+PythonClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "python_xsd.xsd")) 
+
+#-------------------------------------------------------------------------------
+#                         Undo Buffer for PythonCode
+#-------------------------------------------------------------------------------
+
+# Length of the buffer
+UNDO_BUFFER_LENGTH = 20
+
+"""
+Class implementing a buffer of changes made on the current editing model
+"""
+class UndoBuffer:
+
+    # Constructor initialising buffer
+    def __init__(self, currentstate, issaved = False):
+        self.Buffer = []
+        self.CurrentIndex = -1
+        self.MinIndex = -1
+        self.MaxIndex = -1
+        # if current state is defined
+        if currentstate:
+            self.CurrentIndex = 0
+            self.MinIndex = 0
+            self.MaxIndex = 0
+        # Initialising buffer with currentstate at the first place
+        for i in xrange(UNDO_BUFFER_LENGTH):
+            if i == 0:
+                self.Buffer.append(currentstate)
+            else:
+                self.Buffer.append(None)
+        # Initialising index of state saved
+        if issaved:
+            self.LastSave = 0
+        else:
+            self.LastSave = -1
+    
+    # Add a new state in buffer
+    def Buffering(self, currentstate):
+        self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH
+        self.Buffer[self.CurrentIndex] = currentstate
+        # Actualising buffer limits
+        self.MaxIndex = self.CurrentIndex
+        if self.MinIndex == self.CurrentIndex:
+            # If the removed state was the state saved, there is no state saved in the buffer
+            if self.LastSave == self.MinIndex:
+                self.LastSave = -1
+            self.MinIndex = (self.MinIndex + 1) % UNDO_BUFFER_LENGTH
+        self.MinIndex = max(self.MinIndex, 0)
+    
+    # Return current state of buffer
+    def Current(self):
+        return self.Buffer[self.CurrentIndex]
+    
+    # Change current state to previous in buffer and return new current state
+    def Previous(self):
+        if self.CurrentIndex != self.MinIndex:
+            self.CurrentIndex = (self.CurrentIndex - 1) % UNDO_BUFFER_LENGTH
+            return self.Buffer[self.CurrentIndex]
+        return None
+    
+    # Change current state to next in buffer and return new current state
+    def Next(self):
+        if self.CurrentIndex != self.MaxIndex:
+            self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH
+            return self.Buffer[self.CurrentIndex]
+        return None
+    
+    # Return True if current state is the first in buffer
+    def IsFirst(self):
+        return self.CurrentIndex == self.MinIndex
+    
+    # Return True if current state is the last in buffer
+    def IsLast(self):
+        return self.CurrentIndex == self.MaxIndex
+
+    # Note that current state is saved
+    def CurrentSaved(self):
+        self.LastSave = self.CurrentIndex
+        
+    # Return True if current state is saved
+    def IsCurrentSaved(self):
+        return self.LastSave == self.CurrentIndex
+
+class PythonCodeTemplate:
+    
+    def __init__(self):
+        
+        self.PluginMethods.insert(0, 
+                {"bitmap" : opjimg("editPYTHONcode"),
+                 "name" : _("Edit Python File"), 
+                 "tooltip" : _("Edit Python File"),
+                 "method" : "_OpenView"},
+        )
+
+        filepath = self.PythonFileName()
+        
+        self.Buffering = False
+        self.PythonCode = PythonClasses["Python"]()
+        self.PythonBuffer = UndoBuffer(self.Copy(self.PythonCode), False)
+        if os.path.isfile(filepath):
+            xmlfile = open(filepath, 'r')
+            tree = minidom.parse(xmlfile)
+            xmlfile.close()
+            
+            for child in tree.childNodes:
+                if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "Python":
+                    self.PythonCode.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"])
+                    self.PythonBuffer = UndoBuffer(self.Copy(self.PythonCode), True)
+        else:
+            self.OnPlugSave()
+
+    def PluginPath(self):
+        return os.path.join(self.PlugParent.PluginPath(), "modules", self.PlugType)
+
+    def PythonFileName(self):
+        return os.path.join(self.PlugPath(), "python.xml")
+
+    def GetFilename(self):
+        if self.PythonBuffer.IsCurrentSaved():
+            return "python"
+        else:
+            return "~python~"
+
+    def SetPythonCode(self, text):
+        self.PythonCode.settext(text)
+        
+    def GetPythonCode(self):
+        return self.PythonCode.gettext()
+    
+    _View = None
+    def _OpenView(self):
+        if not self._View:
+            def _onclose():
+                self._View = None
+            def _onsave():
+                self.GetPlugRoot().SaveProject()
+            self._View = PythonEditorFrame(self.GetPlugRoot().AppFrame, self)
+            self._View._onclose = _onclose
+            self._View._onsave = _onsave
+            self._View.Show()
+    
+    def OnPlugSave(self):
+        filepath = self.PythonFileName()
+        
+        text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+        extras = {"xmlns":"http://www.w3.org/2001/XMLSchema",
+                  "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
+                  "xsi:schemaLocation" : "python_xsd.xsd"}
+        text += self.PythonCode.generateXMLText("Python", 0, extras)
+
+        xmlfile = open(filepath,"w")
+        xmlfile.write(text)
+        xmlfile.close()
+        
+        self.PythonBuffer.CurrentSaved()
+        return True
+        
+#-------------------------------------------------------------------------------
+#                      Current Buffering Management Functions
+#-------------------------------------------------------------------------------
+
+    """
+    Return a copy of the project
+    """
+    def Copy(self, model):
+        return cPickle.loads(cPickle.dumps(model))
+
+    def BufferPython(self):
+        self.PythonBuffer.Buffering(self.Copy(self.PythonCode))
+    
+    def StartBuffering(self):
+        self.PythonBuffer.Buffering(self.PythonCode)
+        self.Buffering = True
+        
+    def EndBuffering(self):
+        if self.Buffering:
+            self.PythonCode = self.Copy(self.PythonCode)
+            self.Buffering = False
+    
+    def PythonCodeIsSaved(self):
+        if self.PythonBuffer:
+            return self.PythonBuffer.IsCurrentSaved()
+        else:
+            return True
+
+    def LoadPrevious(self):
+        self.PythonCode = self.Copy(self.PythonBuffer.Previous())
+    
+    def LoadNext(self):
+        self.PythonCode = self.Copy(self.PythonBuffer.Next())
+    
+    def GetBufferState(self):
+        first = self.PythonBuffer.IsFirst()
+        last = self.PythonBuffer.IsLast()
+        return not first, not last
+
+def _GetClassFunction(name):
+    def GetRootClass():
+        __import__("plugins.python.modules." + name)
+        return getattr(modules, name).RootClass
+    return GetRootClass
+
+class RootClass(PythonCodeTemplate):
+
+    # For root object, available Childs Types are modules of the modules packages.
+    PlugChildsTypes = [(name, _GetClassFunction(name), help) for name, help in zip(modules.__all__,modules.helps)]
+    
+    def PluginPath(self):
+        return os.path.join(self.PlugParent.PluginPath(), self.PlugType)
+    
+    def PlugGenerate_C(self, buildpath, locations):
+        """
+        Generate C code
+        @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
+        @param locations: List of complete variables locations \
+            [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
+            "NAME" : name of the variable (generally "__IW0_1_2" style)
+            "DIR" : direction "Q","I" or "M"
+            "SIZE" : size "X", "B", "W", "D", "L"
+            "LOC" : tuple of interger for IEC location (0,1,2,...)
+            }, ...]
+        @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
+        """
+        current_location = self.GetCurrentLocation()
+        # define a unique name for the generated C file
+        location_str = "_".join(map(lambda x:str(x), current_location))
+        
+        plugin_root = self.GetPlugRoot()
+        plugin_root.GetIECProgramsAndVariables()
+        
+        plc_python_filepath = os.path.join(os.path.split(__file__)[0], "plc_python.c")
+        plc_python_file = open(plc_python_filepath, 'r')
+        plc_python_code = plc_python_file.read()
+        plc_python_file.close()
+        python_eval_fb_list = []
+        for v in plugin_root._VariablesList :
+            if v["vartype"] == "FB" and v["type"] in ["PYTHON_EVAL","PYTHON_POLL"]:
+                python_eval_fb_list.append(v)
+        python_eval_fb_count = max(1, len(python_eval_fb_list))
+        
+        # prepare python code
+        plc_python_code = plc_python_code % {
+           "python_eval_fb_count": python_eval_fb_count,
+           "location": location_str}
+        
+        Gen_Pythonfile_path = os.path.join(buildpath, "python_%s.c"%location_str)
+        pythonfile = open(Gen_Pythonfile_path,'w')
+        pythonfile.write(plc_python_code)
+        pythonfile.close()
+        
+        runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str)
+        runtimefile = open(runtimefile_path, 'w')
+        runtimefile.write(self.GetPythonCode())
+        runtimefile.write("""
+def _runtime_%(location)s_begin():
+    print "runtime_begin"
+
+def _runtime_%(location)s_cleanup():
+    print "runtime_cleanup"
+
+""" % {"location": location_str})
+        runtimefile.close()
+        
+        if wx.Platform == '__WXMSW__':
+            matiec_flags = " -I../../matiec/lib"
+        else:
+            matiec_flags = " -I../matiec/lib"
+        
+        return [(Gen_Pythonfile_path, matiec_flags)], "", True, ("runtime_%s.py"%location_str, file(runtimefile_path,"rb"))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/python/python_xsd.xsd	Wed Jul 29 15:17:10 2009 +0200
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<xsd:schema targetNamespace="python_xsd.xsd" 
+            xmlns:cext="python_xsd.xsd" 
+            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+            elementFormDefault="qualified" 
+            attributeFormDefault="unqualified">
+
+  <xsd:element name="Python">
+	  <xsd:complexType>
+	    <xsd:annotation>
+	      <xsd:documentation>Formatted text according to parts of XHTML 1.1</xsd:documentation>
+	    </xsd:annotation>
+	    <xsd:sequence>
+	      <xsd:any namespace="http://www.w3.org/1999/xhtml" processContents="lax"/>
+	    </xsd:sequence>
+	  </xsd:complexType>
+	</xsd:element>
+</xsd:schema>
--- a/pous.xml	Wed Jul 29 10:49:31 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,457 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xmlns="http://www.plcopen.org/xml/tc6.xsd"
-         xmlns:xhtml="http://www.w3.org/1999/xhtml"
-         xsi:schemaLocation="http://www.plcopen.org/xml/tc6.xsd">
-  <fileHeader companyName="LOLITECH"
-              productName="Beremiz"
-              productVersion="0.0"
-              creationDateTime="2008-12-14T16:53:26"/>
-  <contentHeader name="Beremiz non-standard POUs library"
-                 modificationDateTime="2008-12-23T22:35:46">
-    <coordinateInfo>
-      <fbd>
-        <scaling x="0" y="0"/>
-      </fbd>
-      <ld>
-        <scaling x="0" y="0"/>
-      </ld>
-      <sfc>
-        <scaling x="0" y="0"/>
-      </sfc>
-    </coordinateInfo>
-  </contentHeader>
-  <types>
-    <dataTypes/>
-    <pous>
-      <pou name="python_eval" pouType="functionBlock">
-        <interface>
-          <inputVars>
-            <variable name="TRIG">
-              <type>
-                <BOOL/>
-              </type>
-            </variable>
-            <variable name="CODE">
-              <type>
-                <string/>
-              </type>
-            </variable>
-          </inputVars>
-          <outputVars>
-            <variable name="ACK">
-              <type>
-                <BOOL/>
-              </type>
-            </variable>
-            <variable name="RESULT">
-              <type>
-                <string/>
-              </type>
-            </variable>
-          </outputVars>
-          <localVars>
-            <variable name="STATE">
-              <type>
-                <DWORD/>
-              </type>
-            </variable>
-            <variable name="BUFFER">
-              <type>
-                <string/>
-              </type>
-            </variable>
-            <variable name="PREBUFFER">
-              <type>
-                <string/>
-              </type>
-            </variable>
-            <variable name="TRIGM1">
-              <type>
-                <BOOL/>
-              </type>
-            </variable>
-            <variable name="TRIGGED">
-              <type>
-                <BOOL/>
-              </type>
-            </variable>
-          </localVars>
-        </interface>
-        <body>
-          <ST>
-<![CDATA[{extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);}]]>
-          </ST>
-        </body>
-      </pou>
-      <pou name="python_poll" pouType="functionBlock">
-        <interface>
-          <inputVars>
-            <variable name="TRIG">
-              <type>
-                <BOOL/>
-              </type>
-            </variable>
-            <variable name="CODE">
-              <type>
-                <string/>
-              </type>
-            </variable>
-          </inputVars>
-          <outputVars>
-            <variable name="ACK">
-              <type>
-                <BOOL/>
-              </type>
-            </variable>
-            <variable name="RESULT">
-              <type>
-                <string/>
-              </type>
-            </variable>
-          </outputVars>
-          <localVars>
-            <variable name="STATE">
-              <type>
-                <DWORD/>
-              </type>
-            </variable>
-            <variable name="BUFFER">
-              <type>
-                <string/>
-              </type>
-            </variable>
-            <variable name="PREBUFFER">
-              <type>
-                <string/>
-              </type>
-            </variable>
-            <variable name="TRIGM1">
-              <type>
-                <BOOL/>
-              </type>
-            </variable>
-            <variable name="TRIGGED">
-              <type>
-                <BOOL/>
-              </type>
-            </variable>
-          </localVars>
-        </interface>
-        <body>
-          <ST>
-<![CDATA[{extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);}]]>
-          </ST>
-        </body>
-      </pou>
-    <pou name="python_gear" pouType="functionBlock">
-        <interface>
-          <inputVars>
-            <variable name="N">
-              <type>
-                <USINT/>
-              </type>
-            </variable>
-            <variable name="TRIG">
-              <type>
-                <BOOL/>
-              </type>
-            </variable>
-            <variable name="CODE">
-              <type>
-                <string/>
-              </type>
-            </variable>
-          </inputVars>
-          <outputVars>
-            <variable name="ACK">
-              <type>
-                <BOOL/>
-              </type>
-            </variable>
-            <variable name="RESULT">
-              <type>
-                <string/>
-              </type>
-            </variable>
-          </outputVars>
-          <localVars>
-            <variable name="py_eval">
-              <type>
-                <derived name="python_eval"/>
-              </type>
-            </variable>
-            <variable name="COUNTER">
-              <type>
-                <USINT/>
-              </type>
-            </variable>
-          </localVars>
-        </interface>
-        <body>
-          <FBD>
-            <block localId="1" width="125" height="110" typeName="python_eval" instanceName="py_eval">
-              <position x="525" y="580"/>
-              <inputVariables>
-                <variable formalParameter="TRIG">
-                  <connectionPointIn>
-                    <relPosition x="0" y="40"/>
-                    <connection refLocalId="7" formalParameter="OUT">
-                      <position x="525" y="620"/>
-                      <position x="495" y="620"/>
-                      <position x="495" y="575"/>
-                      <position x="465" y="575"/>
-                    </connection>
-                  </connectionPointIn>
-                </variable>
-                <variable formalParameter="CODE">
-                  <connectionPointIn>
-                    <relPosition x="0" y="85"/>
-                    <connection refLocalId="4">
-                      <position x="525" y="665"/>
-                      <position x="370" y="665"/>
-                    </connection>
-                  </connectionPointIn>
-                </variable>
-              </inputVariables>
-              <inOutVariables/>
-              <outputVariables>
-                <variable formalParameter="ACK">
-                  <connectionPointOut>
-                    <relPosition x="125" y="40"/>
-                  </connectionPointOut>
-                </variable>
-                <variable formalParameter="RESULT">
-                  <connectionPointOut>
-                    <relPosition x="125" y="85"/>
-                  </connectionPointOut>
-                </variable>
-              </outputVariables>
-            </block>
-            <inVariable localId="2" height="35" width="25">
-              <position x="435" y="270"/>
-              <connectionPointOut>
-                <relPosition x="25" y="15"/>
-              </connectionPointOut>
-              <expression>N</expression>
-            </inVariable>
-            <inVariable localId="3" height="35" width="55">
-              <position x="275" y="585"/>
-              <connectionPointOut>
-                <relPosition x="55" y="15"/>
-              </connectionPointOut>
-              <expression>TRIG</expression>
-            </inVariable>
-            <inVariable localId="4" height="35" width="55">
-              <position x="315" y="650"/>
-              <connectionPointOut>
-                <relPosition x="55" y="15"/>
-              </connectionPointOut>
-              <expression>CODE</expression>
-            </inVariable>
-            <outVariable localId="5" height="35" width="45">
-              <position x="740" y="605"/>
-              <connectionPointIn>
-                <relPosition x="0" y="15"/>
-                <connection refLocalId="1" formalParameter="ACK">
-                  <position x="740" y="620"/>
-                  <position x="650" y="620"/>
-                </connection>
-              </connectionPointIn>
-              <expression>ACK</expression>
-            </outVariable>
-            <outVariable localId="6" height="35" width="75">
-              <position x="740" y="650"/>
-              <connectionPointIn>
-                <relPosition x="0" y="15"/>
-                <connection refLocalId="1" formalParameter="RESULT">
-                  <position x="740" y="665"/>
-                  <position x="650" y="665"/>
-                </connection>
-              </connectionPointIn>
-              <expression>RESULT</expression>
-            </outVariable>
-            <block localId="7" width="80" height="65" typeName="AND">
-              <position x="385" y="545"/>
-              <inputVariables>
-                <variable formalParameter="IN1">
-                  <connectionPointIn>
-                    <relPosition x="0" y="30"/>
-                    <connection refLocalId="13" formalParameter="OUT">
-                      <position x="385" y="575"/>
-                      <position x="335" y="575"/>
-                      <position x="335" y="455"/>
-                      <position x="625" y="455"/>
-                      <position x="625" y="285"/>
-                      <position x="615" y="285"/>
-                    </connection>
-                  </connectionPointIn>
-                </variable>
-                <variable formalParameter="IN2">
-                  <connectionPointIn>
-                    <relPosition x="0" y="55"/>
-                    <connection refLocalId="3">
-                      <position x="385" y="600"/>
-                      <position x="330" y="600"/>
-                    </connection>
-                  </connectionPointIn>
-                </variable>
-              </inputVariables>
-              <inOutVariables/>
-              <outputVariables>
-                <variable formalParameter="OUT">
-                  <connectionPointOut>
-                    <relPosition x="80" y="30"/>
-                  </connectionPointOut>
-                </variable>
-              </outputVariables>
-            </block>
-            <inVariable localId="9" height="35" width="85">
-              <position x="240" y="330"/>
-              <connectionPointOut>
-                <relPosition x="85" y="15"/>
-              </connectionPointOut>
-              <expression>COUNTER</expression>
-            </inVariable>
-            <block localId="10" width="80" height="65" typeName="ADD">
-              <position x="380" y="330"/>
-              <inputVariables>
-                <variable formalParameter="IN1">
-                  <connectionPointIn>
-                    <relPosition x="0" y="30"/>
-                    <connection refLocalId="9">
-                      <position x="380" y="360"/>
-                      <position x="352" y="360"/>
-                      <position x="352" y="345"/>
-                      <position x="325" y="345"/>
-                    </connection>
-                  </connectionPointIn>
-                </variable>
-                <variable formalParameter="IN2">
-                  <connectionPointIn>
-                    <relPosition x="0" y="55"/>
-                    <connection refLocalId="11">
-                      <position x="380" y="385"/>
-                      <position x="325" y="385"/>
-                    </connection>
-                  </connectionPointIn>
-                </variable>
-              </inputVariables>
-              <inOutVariables/>
-              <outputVariables>
-                <variable formalParameter="OUT">
-                  <connectionPointOut>
-                    <relPosition x="80" y="30"/>
-                  </connectionPointOut>
-                </variable>
-              </outputVariables>
-            </block>
-            <inVariable localId="11" height="35" width="85">
-              <position x="240" y="370"/>
-              <connectionPointOut>
-                <relPosition x="85" y="15"/>
-              </connectionPointOut>
-              <expression>USINT#1</expression>
-            </inVariable>
-            <block localId="13" width="80" height="65" typeName="EQ">
-              <position x="535" y="255"/>
-              <inputVariables>
-                <variable formalParameter="IN1">
-                  <connectionPointIn>
-                    <relPosition x="0" y="30"/>
-                    <connection refLocalId="2">
-                      <position x="535" y="285"/>
-                      <position x="460" y="285"/>
-                    </connection>
-                  </connectionPointIn>
-                </variable>
-                <variable formalParameter="IN2">
-                  <connectionPointIn>
-                    <relPosition x="0" y="55"/>
-                    <connection refLocalId="10" formalParameter="OUT">
-                      <position x="535" y="310"/>
-                      <position x="497" y="310"/>
-                      <position x="497" y="360"/>
-                      <position x="460" y="360"/>
-                    </connection>
-                  </connectionPointIn>
-                </variable>
-              </inputVariables>
-              <inOutVariables/>
-              <outputVariables>
-                <variable formalParameter="OUT">
-                  <connectionPointOut>
-                    <relPosition x="80" y="30"/>
-                  </connectionPointOut>
-                </variable>
-              </outputVariables>
-            </block>
-            <block localId="15" width="80" height="135" typeName="SEL">
-              <position x="785" y="245"/>
-              <inputVariables>
-                <variable formalParameter="G">
-                  <connectionPointIn>
-                    <relPosition x="0" y="40"/>
-                    <connection refLocalId="13" formalParameter="OUT">
-                      <position x="785" y="285"/>
-                      <position x="615" y="285"/>
-                    </connection>
-                  </connectionPointIn>
-                </variable>
-                <variable formalParameter="IN0">
-                  <connectionPointIn>
-                    <relPosition x="0" y="75"/>
-                    <connection refLocalId="10" formalParameter="OUT">
-                      <position x="785" y="320"/>
-                      <position x="650" y="320"/>
-                      <position x="650" y="360"/>
-                      <position x="460" y="360"/>
-                    </connection>
-                  </connectionPointIn>
-                </variable>
-                <variable formalParameter="IN1">
-                  <connectionPointIn>
-                    <relPosition x="0" y="115"/>
-                    <connection refLocalId="16">
-                      <position x="785" y="360"/>
-                      <position x="760" y="360"/>
-                    </connection>
-                  </connectionPointIn>
-                </variable>
-              </inputVariables>
-              <inOutVariables/>
-              <outputVariables>
-                <variable formalParameter="OUT">
-                  <connectionPointOut>
-                    <relPosition x="80" y="40"/>
-                  </connectionPointOut>
-                </variable>
-              </outputVariables>
-            </block>
-            <inVariable localId="16" height="35" width="85">
-              <position x="675" y="345"/>
-              <connectionPointOut>
-                <relPosition x="85" y="15"/>
-              </connectionPointOut>
-              <expression>USINT#0</expression>
-            </inVariable>
-            <outVariable localId="17" height="35" width="85">
-              <position x="905" y="270"/>
-              <connectionPointIn>
-                <relPosition x="0" y="15"/>
-                <connection refLocalId="15" formalParameter="OUT">
-                  <position x="905" y="285"/>
-                  <position x="865" y="285"/>
-                </connection>
-              </connectionPointIn>
-              <expression>COUNTER</expression>
-            </outVariable>
-          </FBD>
-        </body>
-      </pou>
-    </pous>
-  </types>
-  <instances>
-    <configurations/>
-  </instances>
-</project>
--- a/runtime/PLCObject.py	Wed Jul 29 10:49:31 2009 +0200
+++ b/runtime/PLCObject.py	Wed Jul 29 15:17:10 2009 +0200
@@ -53,6 +53,7 @@
         self.PLCStatus = "Stopped"
         self.PLClibraryHandle = None
         self.PLClibraryLock = Lock()
+        self.DummyIteratorLock = None
         # Creates fake C funcs proxies
         self._FreePLC()
         self.daemon = daemon
@@ -93,10 +94,30 @@
             self._startPLC.restype = ctypes.c_int
             self._startPLC.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_char_p)]
             
-            def StopPLCLock():
-                self.PLClibraryLock.acquire()
-                self.PLClibraryHandle.stopPLC()
-                self.PLClibraryLock.release()
+            self.DummyIteratorLock = Lock()
+            self.DummyIteratorLock.acquire()
+            
+            self._PythonIterator = getattr(self.PLClibraryHandle, "PythonIterator", None)
+            if self._PythonIterator is not None:
+                self._PythonIterator.restype = ctypes.c_char_p
+                self._PythonIterator.argtypes = [ctypes.c_char_p]
+                
+                def StopPLCLock():
+                    self.PLClibraryLock.acquire()
+                    self.PLClibraryHandle.stopPLC()
+                    self.PLClibraryLock.release()
+                
+            else:
+                def DummyIterator(res):
+                    self.DummyIteratorLock.acquire()
+                    return None
+                self._PythonIterator = DummyIterator
+                
+                def StopPLCLock():
+                    self.PLClibraryLock.acquire()
+                    self.PLClibraryHandle.stopPLC()
+                    self.DummyIteratorLock.release()
+                    self.PLClibraryLock.release()
             
             self._stopPLC = StopPLCLock
             self._stopPLC.restype = None
@@ -123,10 +144,6 @@
 
             self._resumeDebug = self.PLClibraryHandle.resumeDebug
             self._resumeDebug.restype = None
-
-            self._PythonIterator = self.PLClibraryHandle.PythonIterator
-            self._PythonIterator.restype = ctypes.c_char_p
-            self._PythonIterator.argtypes = [ctypes.c_char_p]
             
             return True
         except:
@@ -188,59 +205,78 @@
     def PrepareRuntimePy(self):
         self.python_threads_vars = globals().copy()
         self.python_threads_vars["WorkingDir"] = self.workingdir
-        pyfile = os.path.join(self.workingdir, "runtime.py")
-        hmifile = os.path.join(self.workingdir, "hmi.py")
-        if os.path.exists(hmifile):
-            try:
-                execfile(hmifile, self.python_threads_vars)
-                if os.path.exists(pyfile):
-                    try:
-                        # TODO handle exceptions in runtime.py
-                        # pyfile may redefine _runtime_cleanup
-                        # or even call _PythonThreadProc itself.
-                        execfile(pyfile, self.python_threads_vars)
-                    except:
-                        PLCprint(traceback.format_exc())
-                if self.python_threads_vars.has_key('wx'):
-                    wx = self.python_threads_vars['wx']
-                    # try to instanciate the first frame found.
-                    for name, obj in self.python_threads_vars.iteritems():
-                        # obj is a class
-                        if type(obj)==type(type) and issubclass(obj,wx.Frame):
-                            def create_frame():
-                                self.hmi_frame = obj(None)
-                                self.python_threads_vars[name] = self.hmi_frame
-                                # keep track of class... never know
-                                self.python_threads_vars['Class_'+name] = obj
-                                self.hmi_frame.Bind(wx.EVT_CLOSE, OnCloseFrame)
-                                self.hmi_frame.Show()
-                            
-                            def OnCloseFrame(evt):
-                                wx.MessageBox(_("Please stop PLC to close"))
-                            create_frame()
-                            break
-            except:
-                PLCprint(traceback.format_exc())
-        elif os.path.exists(pyfile):
-            try:
-                # TODO handle exceptions in runtime.py
-                # pyfile may redefine _runtime_cleanup
-                # or even call _PythonThreadProc itself.
-                execfile(pyfile, self.python_threads_vars)
-            except:
-                PLCprint(traceback.format_exc())
-        runtime_begin = self.python_threads_vars.get("_runtime_begin",None)
-        if runtime_begin is not None:
+        self.python_threads_vars["_runtime_begin"] = []
+        self.python_threads_vars["_runtime_cleanup"] = []
+#        pyfile = os.path.join(self.workingdir, "runtime.py")
+#        hmifile = os.path.join(self.workingdir, "hmi.py")
+#        if os.path.exists(hmifile):
+#            try:
+#                execfile(hmifile, self.python_threads_vars)
+#                if os.path.exists(pyfile):
+#                    try:
+#                        # TODO handle exceptions in runtime.py
+#                        # pyfile may redefine _runtime_cleanup
+#                        # or even call _PythonThreadProc itself.
+#                        execfile(pyfile, self.python_threads_vars)
+#                    except:
+#                        PLCprint(traceback.format_exc())
+#                if self.python_threads_vars.has_key('wx'):
+#                    wx = self.python_threads_vars['wx']
+#                    # try to instanciate the first frame found.
+#                    for name, obj in self.python_threads_vars.iteritems():
+#                        # obj is a class
+#                        if type(obj)==type(type) and issubclass(obj,wx.Frame):
+#                            def create_frame():
+#                                self.hmi_frame = obj(None)
+#                                self.python_threads_vars[name] = self.hmi_frame
+#                                # keep track of class... never know
+#                                self.python_threads_vars['Class_'+name] = obj
+#                                self.hmi_frame.Bind(wx.EVT_CLOSE, OnCloseFrame)
+#                                self.hmi_frame.Show()
+#                            
+#                            def OnCloseFrame(evt):
+#                                wx.MessageBox(_("Please stop PLC to close"))
+#                            create_frame()
+#                            break
+#            except:
+#                PLCprint(traceback.format_exc())
+#        elif os.path.exists(pyfile):
+#            try:
+#                # TODO handle exceptions in runtime.py
+#                # pyfile may redefine _runtime_cleanup
+#                # or even call _PythonThreadProc itself.
+#                execfile(pyfile, self.python_threads_vars)
+#            except:
+#                PLCprint(traceback.format_exc())
+        for filename in os.listdir(self.workingdir):
+            name, ext = os.path.splitext(filename)
+            if name.startswith("runtime") and ext == ".py":
+                try:
+                    # TODO handle exceptions in runtime.py
+                    # pyfile may redefine _runtime_cleanup
+                    # or even call _PythonThreadProc itself.
+                    execfile(os.path.join(self.workingdir, filename), self.python_threads_vars)
+                except:
+                    PLCprint(traceback.format_exc())
+                runtime_begin = self.python_threads_vars.get("_%s_begin" % name, None)
+                if runtime_begin is not None:
+                    self.python_threads_vars["_runtime_begin"].append(runtime_begin)
+                runtime_cleanup = self.python_threads_vars.get("_%s_cleanup" % name, None)
+                if runtime_cleanup is not None:
+                    self.python_threads_vars["_runtime_cleanup"].append(runtime_cleanup)
+        
+        for runtime_begin in self.python_threads_vars.get("_runtime_begin", []):
             runtime_begin()
 
     def FinishRuntimePy(self):
-        runtime_cleanup = None
-        if self.python_threads_vars is not None:
-            runtime_cleanup = self.python_threads_vars.get("_runtime_cleanup",None)
-        if runtime_cleanup is not None:
-            runtime_cleanup()
-        if self.hmi_frame is not None:
-            self.hmi_frame.Destroy()
+        for runtime_cleanup in self.python_threads_vars.get("_runtime_cleanup", []):
+            runtime_cleanup()    
+#        if self.python_threads_vars is not None:
+#            runtime_cleanup = self.python_threads_vars.get("_runtime_cleanup",None)
+#        if runtime_cleanup is not None:
+#            runtime_cleanup()
+#        if self.hmi_frame is not None:
+#            self.hmi_frame.Destroy()
         self.python_threads_vars = None
 
     def PythonThreadProc(self, debug):
--- a/targets/plc_common_main.c	Wed Jul 29 10:49:31 2009 +0200
+++ b/targets/plc_common_main.c	Wed Jul 29 15:17:10 2009 +0200
@@ -18,11 +18,6 @@
 /*void __retrieve_debug(void);*/
 void __publish_debug(void);
 
-void __init_python(void);
-void __cleanup_python(void);
-void __retrieve_python(void);
-void __publish_python(void);
-
 /*
  *  Variables used by generated C softPLC and plugins
  **/
@@ -47,14 +42,10 @@
 
     %(retrieve_calls)s
 
-    __retrieve_python();
-
     /*__retrieve_debug();*/
 
     config_run__(__tick);
 
-    __publish_python();
-
     __publish_debug();
 
     %(publish_calls)s
@@ -71,7 +62,6 @@
     setlocale(LC_NUMERIC, "C");
     config_init__();
     __init_debug();
-    __init_python();
     %(init_calls)s
     return 0;
 }
@@ -82,7 +72,6 @@
 {
     %(cleanup_calls)s
     __cleanup_debug();
-    __cleanup_python();
 }
 
 
--- a/targets/plc_python.c	Wed Jul 29 10:49:31 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,213 +0,0 @@
-/*
- * Python Asynchronous execution code
- *
- * PLC put python commands in a fifo, respecting execution order
- * with the help of C pragmas inserted in python_eval FB code
- *
- * Buffer content is read asynchronously, (from non real time part),
- * commands are executed and result stored for later use by PLC.
- *
- * In this implementation, fifo is a list of pointer to python_eval
- * function blocks structures. Some local variables have been added in
- * python_eval interface. We use those local variables as buffer and state
- * flags.
- *
- * */
-
-#include "iec_types_all.h"
-#include "POUS.h"
-#include <string.h>
-
-/* The fifo (fixed size, as number of FB is fixed) */
-static PYTHON_EVAL* EvalFBs[%(python_eval_fb_count)d];
-/* Producer and consumer cursors */
-static int Current_PLC_EvalFB;
-static int Current_Python_EvalFB;
-
-/* A global IEC-Python gateway state, for use inside python_eval FBs*/
-static int PythonState;
-#define PYTHON_LOCKED_BY_PYTHON 0
-#define PYTHON_LOCKED_BY_PLC 1
-#define PYTHON_MUSTWAKEUP 2
-#define PYTHON_FINISHED 4
-
-/* Each python_eval FunctionBlock have it own state */
-#define PYTHON_FB_FREE 0
-#define PYTHON_FB_REQUESTED 1
-#define PYTHON_FB_PROCESSING 2
-#define PYTHON_FB_ANSWERED 3
-
-int WaitPythonCommands(void);
-void UnBlockPythonCommands(void);
-int TryLockPython(void);
-void UnLockPython(void);
-void LockPython(void);
-
-void __init_python()
-{
-	int i;
-	/* Initialize cursors */
-	Current_Python_EvalFB = 0;
-	Current_PLC_EvalFB = 0;
-	PythonState = PYTHON_LOCKED_BY_PYTHON;
-	for(i = 0; i < %(python_eval_fb_count)d; i++)
-		EvalFBs[i] = NULL;
-}
-
-void __cleanup_python()
-{
-	PythonState = PYTHON_FINISHED;
-	UnBlockPythonCommands();
-}
-
-void __retrieve_python()
-{
-	/* Check Python thread is not being
-	 * modifying internal python_eval data */
-	PythonState = TryLockPython() ?
-	                PYTHON_LOCKED_BY_PLC :
-	                PYTHON_LOCKED_BY_PYTHON;
-	/* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON
-	 * and python_eval will no do anything */
-}
-
-void __publish_python()
-{
-	if(PythonState & PYTHON_LOCKED_BY_PLC){
-		/* If runnig PLC did push something in the fifo*/
-		if(PythonState & PYTHON_MUSTWAKEUP){
-			/* WakeUp python thread */
-			UnBlockPythonCommands();
-		}
-		UnLockPython();
-	}
-}
-/**
- * Called by the PLC, each time a python_eval
- * FB instance is executed
- */
-void __PythonEvalFB(int poll, PYTHON_EVAL* data__)
-{
-	/* detect rising edge on TRIG to trigger evaluation */
-	if(((data__->TRIG && !data__->TRIGM1) ||
-	   /* polling is equivalent to trig on value rather than on rising edge*/
-	    (poll && data__->TRIG )) &&
-	    /* trig only if not already trigged */
-	   data__->TRIGGED == 0){
-		/* mark as trigged */
-		data__->TRIGGED = 1;
-		/* make a safe copy of the code */
-		data__->PREBUFFER = data__->CODE;
-	}
-	/* retain value for next rising edge detection */
-	data__->TRIGM1 = data__->TRIG;
-
-	/* python thread is not in ? */
-	if( PythonState & PYTHON_LOCKED_BY_PLC){
-		/* if some answer are waiting, publish*/
-		if(data__->STATE == PYTHON_FB_ANSWERED){
-			/* Copy buffer content into result*/
-			data__->RESULT = data__->BUFFER;
-			/* signal result presece to PLC*/
-			data__->ACK = 1;
-			/* Mark as free */
-			data__->STATE = PYTHON_FB_FREE;
-			/* mark as not trigged */
-			if(!poll)
-				data__->TRIGGED = 0;
-			/*printf("__PythonEvalFB pop %%d - %%*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/
-		}else if(poll){
-			/* when in polling, no answer == ack down */
-			data__->ACK = 0;
-		}
-		/* got the order to act ?*/
-		if(data__->TRIGGED == 1 &&
-		   /* and not already being processed */
-		   data__->STATE == PYTHON_FB_FREE)
-		{
-			/* Enter the block in the fifo
-			/* Don't have to check if fifo cell is free
-			 * as fifo size == FB count, and a FB cannot
-			 * be requested twice */
-			EvalFBs[Current_PLC_EvalFB] = data__;
-			/* copy into BUFFER local*/
-			data__->BUFFER = data__->PREBUFFER;
-			/* Set ACK pin to low so that we can set a rising edge on result */
-			if(!poll){
-				/* when not polling, a new answer imply reseting ack*/
-				data__->ACK = 0;
-			}else{
-				/* when in polling, acting reset trigger */
-				data__->TRIGGED = 0;
-			}
-			/* Mark FB busy */
-			data__->STATE = PYTHON_FB_REQUESTED;
-			/* Have to wakeup python thread in case he was asleep */
-			PythonState |= PYTHON_MUSTWAKEUP;
-			/*printf("__PythonEvalFB push %%d - %%*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/
-			/* Get a new line */
-			Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) %% %(python_eval_fb_count)d;
-		}
-	}
-}
-
-char* PythonIterator(char* result)
-{
-	char* next_command;
-	PYTHON_EVAL* data__;
-	//printf("PythonIterator result %%s\n", result);
-	/* take python mutex to prevent changing PLC data while PLC running */
-	LockPython();
-	/* Get current FB */
-	data__ = EvalFBs[Current_Python_EvalFB];
-	if(data__ && /* may be null at first run */
-	   data__->STATE == PYTHON_FB_PROCESSING){ /* some answer awaited*/
-	   	/* If result not None */
-	   	if(result){
-			/* Get results len */
-			data__->BUFFER.len = strlen(result);
-			/* prevent results overrun */
-			if(data__->BUFFER.len > STR_MAX_LEN)
-			{
-				data__->BUFFER.len = STR_MAX_LEN;
-				/* TODO : signal error */
-			}
-			/* Copy results to buffer */
-			strncpy(data__->BUFFER.body, result, data__->BUFFER.len);
-	   	}else{
-	   		data__->BUFFER.len = 0;
-	   	}
-		/* remove block from fifo*/
-		EvalFBs[Current_Python_EvalFB] = NULL;
-		/* Mark block as answered */
-		data__->STATE = PYTHON_FB_ANSWERED;
-		/* Get a new line */
-		Current_Python_EvalFB = (Current_Python_EvalFB + 1) %% %(python_eval_fb_count)d;
-		//printf("PythonIterator ++ Current_Python_EvalFB %%d\n", Current_Python_EvalFB);
-	}
-	/* while next slot is empty */
-	while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) ||
-	 	  /* or doesn't contain command */
-	      data__->STATE != PYTHON_FB_REQUESTED)
-	{
-		UnLockPython();
-		/* wait next FB to eval */
-		//printf("PythonIterator wait\n");
-		if(WaitPythonCommands()) return NULL;
-		/*emergency exit*/
-		if(PythonState & PYTHON_FINISHED) return NULL;
-		LockPython();
-	}
-	/* Mark block as processing */
-	data__->STATE = PYTHON_FB_PROCESSING;
-	//printf("PythonIterator\n");
-	/* make BUFFER a null terminated string */
-	data__->BUFFER.body[data__->BUFFER.len] = 0;
-	/* next command is BUFFER */
-	next_command = data__->BUFFER.body;
-	/* free python mutex */
-	UnLockPython();
-	/* return the next command to eval */
-	return next_command;
-}
-
--- a/tests/python/plc.xml	Wed Jul 29 10:49:31 2009 +0200
+++ b/tests/python/plc.xml	Wed Jul 29 15:17:10 2009 +0200
@@ -8,7 +8,7 @@
               productVersion="0.0"
               creationDateTime="2008-12-14T16:21:19"/>
   <contentHeader name="Beremiz Python Support Tests"
-                 modificationDateTime="2008-12-30T00:26:11">
+                 modificationDateTime="2009-07-29T14:39:02">
     <coordinateInfo>
       <pageSize x="1024" y="1024"/>
       <fbd>
@@ -466,8 +466,8 @@
     <configurations>
       <configuration name="conf_pytest">
         <resource name="res_pytest">
-          <task name="pytest_task" interval="00:00:00.100000" priority="0"/>
-          <pouInstance name="pytest_instance" type="main_pytest"/>
+          <task name="pytest_task" interval="t#100ms" priority="0"/>
+          <pouInstance name="pytest_instance" typeName="main_pytest"/>
         </resource>
       </configuration>
     </configurations>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/python/python@python/baseplugin.xml	Wed Jul 29 15:17:10 2009 +0200
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BaseParams Name="python" IEC_Channel="0"/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/python/python@python/python.xml	Wed Jul 29 15:17:10 2009 +0200
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<Python xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="python_xsd.xsd">
+<![CDATA[import time,sys
+def myprintfunc(arg):
+    print arg
+    sys.stdout.flush()
+    return arg]]>
+</Python>
--- a/tests/python/runtime.py	Wed Jul 29 10:49:31 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-import time,sys
-def myprintfunc(arg):
-    print arg
-    sys.stdout.flush()
-    return arg