merged Sergeys changes
authorEdouard Tisserant <edouard.tisserant@gmail.com>
Fri, 02 Mar 2018 17:01:25 +0100
changeset 1973 cc7a46953471
parent 1961 b4a1ba9dbaf3 (diff)
parent 1972 38e912c8bd31 (current diff)
child 1975 6b357f1e3134
child 2012 6e3f757280dc
merged Sergeys changes
PLCControler.py
controls/DebugVariablePanel/DebugVariableGraphicViewer.py
controls/ProjectPropertiesPanel.py
controls/VariablePanel.py
plcopen/BlockInstanceCollector.py
plcopen/POUVariablesCollector.py
runtime/loglevels.py
runtime/typemapping.py
--- a/Beremiz.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/Beremiz.py	Fri Mar 02 17:01:25 2018 +0100
@@ -28,10 +28,9 @@
 import os
 import sys
 import getopt
-import time
 
 import wx
-from wx.lib.agw.advancedsplash import AdvancedSplash
+from wx.lib.agw.advancedsplash import AdvancedSplash, AS_NOTIMEOUT, AS_CENTER_ON_SCREEN
 
 import util.paths as paths
 
@@ -47,24 +46,13 @@
         self.buildpath = None
         self.splash = None
         self.splashPath = self.Bpath("images", "splash.png")
+        self.modules = ["BeremizIDE"]
+        self.debug = os.path.exists("BEREMIZ_DEBUG")
+        self.handle_exception = None
 
     def Bpath(self, *args):
         return os.path.join(self.app_dir, *args)
 
-    def ShowSplashScreen(self):
-        bmp = wx.Image(self.splashPath).ConvertToBitmap()
-        self.splash = AdvancedSplash(None, bitmap=bmp)
-
-        # process all events
-        # even the events generated by splash themself during showing
-        if wx.Platform == '__WXMSW__':
-            self.splash.Show()
-            self.splash.ProcessEvent(wx.PaintEvent())
-        else:
-            for dummy in range(0, 30):
-                wx.Yield()
-                time.sleep(0.01)
-
     def Usage(self):
         print("Usage:")
         print("%s [Options] [Projectpath] [Buildpath]" % sys.argv[0])
@@ -113,32 +101,46 @@
             self.buildpath = args[1]
 
     def CreateApplication(self):
-        BMZ_DBG = os.path.exists("BEREMIZ_DEBUG")
-
-        if wx.VERSION >= (3, 0, 0):
-            self.app = wx.App(redirect=BMZ_DBG)
-        else:
-            self.app = wx.PySimpleApp(redirect=BMZ_DBG)
-
+
+        BeremizAppType = wx.App if wx.VERSION >= (3, 0, 0) else wx.PySimpleApp
+
+        class BeremizApp(BeremizAppType):
+            def OnInit(_self):  # pylint: disable=no-self-argument
+                self.ShowSplashScreen()
+                return True
+
+        self.app = BeremizApp(redirect=self.debug)
         self.app.SetAppName('beremiz')
         if wx.VERSION < (3, 0, 0):
             wx.InitAllImageHandlers()
 
-        self.ShowSplashScreen()
-        self.BackgroundInitialization()
+    def ShowSplashScreen(self):
+        class Splash(AdvancedSplash):
+            def OnPaint(_self, event):  # pylint: disable=no-self-argument
+                AdvancedSplash.OnPaint(_self, event)
+                wx.CallAfter(self.AppStart)
+        bmp = wx.Image(self.splashPath).ConvertToBitmap()
+        self.splash = Splash(None,
+                             bitmap=bmp,
+                             agwStyle=AS_NOTIMEOUT | AS_CENTER_ON_SCREEN)
 
     def BackgroundInitialization(self):
         self.InitI18n()
         self.CheckUpdates()
         self.LoadExtensions()
         self.ImportModules()
-        self.InstallExceptionHandler()
-        self.ShowUI()
 
     def InitI18n(self):
         from util.misc import InstallLocalRessources
         InstallLocalRessources(self.app_dir)
 
+    def globals(self):
+        """
+        allows customizations to specify what globals
+        are passed to extensions
+        """
+        return globals()
+
     def LoadExtensions(self):
         for extfilename in self.extensions:
             from util.TranslationCatalogs import AddCatalog
@@ -147,7 +149,7 @@
             sys.path.append(extension_folder)
             AddCatalog(os.path.join(extension_folder, "locale"))
             AddBitmapFolder(os.path.join(extension_folder, "images"))
-            execfile(extfilename, locals())
+            execfile(extfilename, self.globals())
 
     def CheckUpdates(self):
         if self.updateinfo_url is not None:
@@ -168,30 +170,49 @@
             self.splash.SetText(text=self.updateinfo)
 
     def ImportModules(self):
-        global BeremizIDE
-        import BeremizIDE
+        for modname in self.modules:
+            mod = __import__(modname)
+            setattr(self, modname, mod)
 
     def InstallExceptionHandler(self):
         import version
         import util.ExceptionHandler
-        util.ExceptionHandler.AddExceptHook(version.app_version)
-
-    def ShowUI(self):
-        import BeremizIDE
-        self.frame = BeremizIDE.Beremiz(None, self.projectOpen, self.buildpath)
+        self.handle_exception = util.ExceptionHandler.AddExceptHook(version.app_version)
+
+    def CreateUI(self):
+        self.frame = self.BeremizIDE.Beremiz(None, self.projectOpen, self.buildpath)
+
+    def CloseSplash(self):
         if self.splash:
             self.splash.Close()
+
+    def ShowUI(self):
         self.frame.Show()
 
     def PreStart(self):
         self.ProcessCommandLineArgs()
         self.CreateApplication()
 
+    def AppStart(self):
+        try:
+            self.BackgroundInitialization()
+            self.CreateUI()
+            self.CloseSplash()
+            self.ShowUI()
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except Exception:
+            if self.handle_exception is not None:
+                self.handle_exception(*sys.exc_info(), exit=True)
+            else:
+                raise
+
     def MainLoop(self):
         self.app.MainLoop()
 
     def Start(self):
         self.PreStart()
+        self.InstallExceptionHandler()
         self.MainLoop()
 
 
--- a/BeremizIDE.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/BeremizIDE.py	Fri Mar 02 17:01:25 2018 +0100
@@ -56,7 +56,8 @@
 from controls import EnhancedStatusBar as esb
 from dialogs.AboutDialog import ShowAboutDialog
 
-from PLCControler import \
+from plcopen.types_enums import \
+    ComputeConfigurationName, \
     LOCATION_CONFNODE, \
     LOCATION_MODULE, \
     LOCATION_GROUP, \
@@ -64,9 +65,10 @@
     LOCATION_VAR_OUTPUT, \
     LOCATION_VAR_MEMORY, \
     ITEM_PROJECT, \
-    ITEM_RESOURCE
-
-from ProjectController import ProjectController, GetAddMenuItems, MATIEC_ERROR_MODEL, ITEM_CONFNODE
+    ITEM_RESOURCE, \
+    ITEM_CONFNODE
+
+from ProjectController import ProjectController, GetAddMenuItems, MATIEC_ERROR_MODEL
 
 from IDEFrame import \
     TITLE,\
@@ -455,7 +457,7 @@
                 self.ProjectTree.Enable(True)
                 self.PouInstanceVariablesPanel.SetController(self.Controler)
                 self.RefreshConfigRecentProjects(os.path.abspath(projectOpen))
-                self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
+                self.RefreshAfterLoad()
             else:
                 self.ResetView()
                 self.ShowErrorMessage(result)
@@ -463,10 +465,11 @@
             self.CTR = ctr
             self.Controler = ctr
             if ctr is not None:
+                ctr.SetAppFrame(self, self.Log)
                 self.LibraryPanel.SetController(self.Controler)
                 self.ProjectTree.Enable(True)
                 self.PouInstanceVariablesPanel.SetController(self.Controler)
-                self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
+                self.RefreshAfterLoad()
         if self.EnableDebug:
             self.DebugVariablePanel.SetDataProducer(self.CTR)
 
@@ -823,7 +826,6 @@
 
     def ResetView(self):
         IDEFrame.ResetView(self)
-        self.ConfNodeInfos = {}
         if self.CTR is not None:
             self.CTR.CloseProject()
         self.CTR = None
@@ -877,7 +879,7 @@
                 self.RefreshConfigRecentProjects(projectpath)
                 if self.EnableDebug:
                     self.DebugVariablePanel.SetDataProducer(self.CTR)
-                self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
+                self.RefreshAfterLoad()
                 IDEFrame.OnAddNewProject(self, event)
             else:
                 self.ResetView()
@@ -916,7 +918,7 @@
                 self.PouInstanceVariablesPanel.SetController(self.Controler)
                 if self.EnableDebug:
                     self.DebugVariablePanel.SetDataProducer(self.CTR)
-                self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
+                self.RefreshAfterLoad()
             else:
                 self.ResetView()
                 self.ShowErrorMessage(result)
@@ -936,6 +938,13 @@
         self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
         self.RefreshAll()
 
+    def RefreshAfterLoad(self):
+        self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
+
+    def RefreshAfterSave(self):
+        self.RefreshAll()
+        self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
+
     def OnSaveProjectMenu(self, event):
         selected = self.TabsOpened.GetSelection()
         if selected != -1:
@@ -943,8 +952,7 @@
             window.Save()
         if self.CTR is not None:
             self.CTR.SaveProject()
-            self.RefreshAll()
-            self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
+            self.RefreshAfterSave()
 
     def OnSaveProjectAsMenu(self, event):
         selected = self.TabsOpened.GetSelection()
@@ -953,9 +961,8 @@
             window.SaveAs()
         if self.CTR is not None:
             self.CTR.SaveProjectAs()
-            self.RefreshAll()
+            self.RefreshAfterSave()
             self.RefreshConfigRecentProjects(self.CTR.ProjectPath)
-            self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
 
     def OnQuitMenu(self, event):
         self.Close()
@@ -1088,7 +1095,7 @@
 
     def ShowHighlight(self, infos, start, end, highlight_type):
         config_name = self.Controler.GetProjectMainConfigurationName()
-        if config_name is not None and infos[0] == self.Controler.ComputeConfigurationName(config_name):
+        if config_name is not None and infos[0] == ComputeConfigurationName(config_name):
             self.CTR._OpenView()
             selected = self.TabsOpened.GetSelection()
             if selected != -1:
--- a/Beremiz_service.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/Beremiz_service.py	Fri Mar 02 17:01:25 2018 +0100
@@ -50,8 +50,9 @@
            -a        - autostart PLC (0:disable 1:enable) (default:0)
            -x        - enable/disable wxTaskbarIcon (0:disable 1:enable) (default:1)
            -t        - enable/disable Twisted web interface (0:disable 1:enable) (default:1)
-           -w        - web server port or "off" (default:8009)
-           -c        - WAMP client config file or "off" (default:wampconf.json)
+           -w        - web server port or "off" to disable web server (default:8009)
+           -c        - WAMP client default config file (default:wampconf.json)
+           -s        - WAMP client secret, given as a file
            -e        - python extension (absolute path .py)
 
            working_dir - directory where are stored PLC files
@@ -59,7 +60,7 @@
 
 
 try:
-    opts, argv = getopt.getopt(sys.argv[1:], "i:p:n:x:t:a:w:c:e:h")
+    opts, argv = getopt.getopt(sys.argv[1:], "i:p:n:x:t:a:w:c:e:s:h")
 except getopt.GetoptError, err:
     # print help information and exit:
     print(str(err))  # will print something like "option -a not recognized"
@@ -70,7 +71,8 @@
 given_ip = None
 port = 3000
 webport = 8009
-wampconf = "wampconf.json"
+wampsecret = None
+wampconf = None
 servicename = None
 autostart = False
 enablewx = True
@@ -105,8 +107,12 @@
         webport = None if a == "off" else int(a)
     elif o == "-c":
         wampconf = None if a == "off" else a
+    elif o == "-s":
+        wampsecret = None if a == "off" else a
     elif o == "-e":
-        extensions.append(a)
+        fnameanddirname = list(os.path.split(os.path.realpath(a)))
+        fnameanddirname.reverse()
+        extensions.append(fnameanddirname)
     else:
         usage()
         sys.exit()
@@ -167,6 +173,8 @@
         # __builtin__.__dict__['_'] = wx.GetTranslation
 
 
+# Life is hard... have a candy.
+# pylint: disable=wrong-import-position,wrong-import-order
 if enablewx:
     try:
         import wx
@@ -319,20 +327,20 @@
                                _("IP is not valid!"))])
                 if dlg.ShowModal() == wx.ID_OK:
                     self.pyroserver.ip_addr = dlg.GetValue()
-                    self.pyroserver.Stop()
+                    self.pyroserver.Restart()
 
             def OnTaskBarChangePort(self, evt):
                 dlg = ParamsEntryDialog(None, _("Enter a port number "), defaultValue=str(self.pyroserver.port))
                 dlg.SetTests([(UnicodeType.isdigit, _("Port number must be an integer!")), (lambda port: 0 <= int(port) <= 65535, _("Port number must be 0 <= port <= 65535!"))])
                 if dlg.ShowModal() == wx.ID_OK:
                     self.pyroserver.port = int(dlg.GetValue())
-                    self.pyroserver.Stop()
+                    self.pyroserver.Restart()
 
             def OnTaskBarChangeWorkingDir(self, evt):
                 dlg = wx.DirDialog(None, _("Choose a working directory "), self.pyroserver.workdir, wx.DD_NEW_DIR_BUTTON)
                 if dlg.ShowModal() == wx.ID_OK:
                     self.pyroserver.workdir = dlg.GetPath()
-                    self.pyroserver.Stop()
+                    self.pyroserver.Restart()
 
             def OnTaskBarChangeName(self, evt):
                 servicename = self.pyroserver.servicename
@@ -412,24 +420,31 @@
 
     def Loop(self):
         while self.continueloop:
+            pyro.initServer()
+            self.daemon = pyro.Daemon(host=self.ip_addr, port=self.port)
+            # pyro never frees memory after connection close if no timeout set
+            # taking too small timeout value may cause
+            # unwanted diconnection when IDE is kept busy for long periods
+            self.daemon.setTimeout(60)
             self.Start()
+            self.daemon.requestLoop()
+            self.daemon.sock.close()
 
     def Restart(self):
-        self.Stop()
+        self._stop()
 
     def Quit(self):
         self.continueloop = False
         if self.plcobj is not None:
             self.plcobj.StopPLC()
             self.plcobj.UnLoadPLC()
-        self.Stop()
+        self._stop()
 
     def Start(self):
-        pyro.initServer()
-        self.daemon = pyro.Daemon(host=self.ip_addr, port=self.port)
         self.plcobj = PLCObject(self.workdir, self.daemon, self.argv,
                                 self.statuschange, self.evaluator,
                                 self.pyruntimevars)
+
         uri = self.daemon.connect(self.plcobj, "PLCObject")
 
         print(_("Pyro port :"), self.port)
@@ -458,10 +473,7 @@
 
         sys.stdout.flush()
 
-        self.daemon.requestLoop()
-        self.daemon.sock.close()
-
-    def Stop(self):
+    def _stop(self):
         if self.plcobj is not None:
             self.plcobj.StopPLC()
         if self.servicepublisher is not None:
@@ -489,7 +501,6 @@
 statuschange = []
 
 if havetwisted:
-
     if havewx:
         reactor.registerWxApp(app)
 
@@ -528,14 +539,21 @@
                         statuschange, pyruntimevars=pyruntimevars)
 
 
-# Exception hooks s
+# Exception hooks
+
+
+def LogMessageAndException(msg, exp=None):
+    if exp is None:
+        exp = sys.exc_info()
+    if pyroserver.plcobj is not None:
+        pyroserver.plcobj.LogMessage(0, msg + '\n'.join(traceback.format_exception(*exp)))
+    else:
+        print(msg)
+        traceback.print_exception(*exp)
 
 
 def LogException(*exp):
-    if pyroserver.plcobj is not None:
-        pyroserver.plcobj.LogMessage(0, '\n'.join(traceback.format_exception(*exp)))
-    else:
-        traceback.print_exception(*exp)
+    LogMessageAndException("", exp)
 
 
 sys.excepthook = LogException
@@ -570,6 +588,13 @@
             webport = None
         NS.WorkingDir = WorkingDir
 
+    # Find pre-existing project WAMP config file
+    _wampconf = os.path.join(WorkingDir, "wampconf.json")
+
+    # If project's WAMP config file exits, override default (-c)
+    if os.path.exists(_wampconf):
+        wampconf = _wampconf
+
     if wampconf is not None:
         try:
             import runtime.WampClient as WC  # pylint: disable=ungrouped-imports
@@ -578,10 +603,9 @@
             wampconf = None
 
 # Load extensions
-for extfilename in extensions:
-    extension_folder = os.path.split(os.path.realpath(extfilename))[0]
+for extention_file, extension_folder in extensions:
     sys.path.append(extension_folder)
-    execfile(extfilename, locals())
+    execfile(os.path.join(extension_folder, extention_file), locals())
 
 if havetwisted:
     if webport is not None:
@@ -589,16 +613,23 @@
             website = NS.RegisterWebsite(webport)
             pyruntimevars["website"] = website
             statuschange.append(NS.website_statuslistener_factory(website))
-        except Exception, e:
-            print(_("Nevow Web service failed. "), e)
+        except Exception:
+            LogMessageAndException(_("Nevow Web service failed. "))
 
     if wampconf is not None:
         try:
-            WC.RegisterWampClient(wampconf)
-            pyruntimevars["wampsession"] = WC.GetSession
-            WC.SetServer(pyroserver)
-        except Exception, e:
-            print(_("WAMP client startup failed. "), e)
+            _wampconf = WC.LoadWampClientConf(wampconf)
+            if _wampconf:
+                if _wampconf["url"]:  # TODO : test more ?
+                    WC.RegisterWampClient(wampconf, wampsecret)
+                    pyruntimevars["wampsession"] = WC.GetSession
+                    WC.SetServer(pyroserver)
+                else:
+                    raise Exception(_("WAMP config is incomplete."))
+            else:
+                raise Exception(_("WAMP config is missing."))
+        except Exception:
+            LogMessageAndException(_("WAMP client startup failed. "))
 
 
 if havetwisted or havewx:
@@ -612,7 +643,7 @@
 else:
     try:
         pyroserver.Loop()
-    except KeyboardInterrupt, e:
+    except KeyboardInterrupt:
         pass
 pyroserver.Quit()
 sys.exit(0)
--- a/ConfigTreeNode.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/ConfigTreeNode.py	Fri Mar 02 17:01:25 2018 +0100
@@ -410,15 +410,16 @@
             res = "%s_%d" % (BaseDesiredName, suffix)
             suffix += 1
 
-        # Get old path
-        oldname = self.CTNPath()
         # Check previous confnode existance
         dontexist = self.BaseParams.getName() == "__unnamed__"
+        if not dontexist:
+            # Get old path
+            oldpath = self.CTNPath()
         # Set the new name
         self.BaseParams.setName(res)
         # Rename confnode dir if exist
         if not dontexist:
-            shutil.move(oldname, self.CTNPath())
+            shutil.move(oldpath, self.CTNPath())
         # warn user he has two left hands
         if DesiredName != res:
             msg = _("A child named \"{a1}\" already exists -> \"{a2}\"\n").format(a1=DesiredName, a2=res)
--- a/IDEFrame.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/IDEFrame.py	Fri Mar 02 17:01:25 2018 +0100
@@ -44,6 +44,7 @@
 from controls.DebugVariablePanel import DebugVariablePanel
 from dialogs import ProjectDialog, PouDialog, PouTransitionDialog, PouActionDialog, FindInPouDialog, SearchInProjectDialog
 from util.BitmapLibrary import GetBitmap
+from plcopen.types_enums import *
 
 # Define PLCOpenEditor controls id
 [
@@ -824,7 +825,7 @@
                 return notebook.GetPageIndex(page_ref)
         elif page_infos[0] == "editor":
             tagname = page_infos[1]
-            page_ref = self.EditProjectElement(self.Controler.GetElementType(tagname), tagname)
+            page_ref = self.EditProjectElement(GetElementType(tagname), tagname)
             if page_ref is not None:
                 page_ref.RefreshView()
                 return notebook.GetPageIndex(page_ref)
@@ -1646,8 +1647,8 @@
                         abort = True
                     if not abort:
                         self.Controler.ChangeDataTypeName(old_name, new_name)
-                        self.RefreshEditorNames(self.Controler.ComputeDataTypeName(old_name),
-                                                self.Controler.ComputeDataTypeName(new_name))
+                        self.RefreshEditorNames(ComputeDataTypeName(old_name),
+                                                ComputeDataTypeName(new_name))
                         self.RefreshPageTitles()
                 elif item_infos["type"] == ITEM_POU:
                     if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames() if name != old_name]:
@@ -1660,8 +1661,8 @@
                         messageDialog.Destroy()
                     if not abort:
                         self.Controler.ChangePouName(old_name, new_name)
-                        self.RefreshEditorNames(self.Controler.ComputePouName(old_name),
-                                                self.Controler.ComputePouName(new_name))
+                        self.RefreshEditorNames(ComputePouName(old_name),
+                                                ComputePouName(new_name))
                         self.RefreshLibraryPanel()
                         self.RefreshPageTitles()
                 elif item_infos["type"] == ITEM_TRANSITION:
@@ -1674,8 +1675,8 @@
                     else:
                         words = item_infos["tagname"].split("::")
                         self.Controler.ChangePouTransitionName(words[1], old_name, new_name)
-                        self.RefreshEditorNames(self.Controler.ComputePouTransitionName(words[1], old_name),
-                                                self.Controler.ComputePouTransitionName(words[1], new_name))
+                        self.RefreshEditorNames(ComputePouTransitionName(words[1], old_name),
+                                                ComputePouTransitionName(words[1], new_name))
                         self.RefreshPageTitles()
                 elif item_infos["type"] == ITEM_ACTION:
                     pou_item = self.ProjectTree.GetItemParent(event.GetItem())
@@ -1687,8 +1688,8 @@
                     else:
                         words = item_infos["tagname"].split("::")
                         self.Controler.ChangePouActionName(words[1], old_name, new_name)
-                        self.RefreshEditorNames(self.Controler.ComputePouActionName(words[1], old_name),
-                                                self.Controler.ComputePouActionName(words[1], new_name))
+                        self.RefreshEditorNames(ComputePouActionName(words[1], old_name),
+                                                ComputePouActionName(words[1], new_name))
                         self.RefreshPageTitles()
                 elif item_infos["type"] == ITEM_CONFIGURATION:
                     if new_name.upper() in [name.upper() for name in self.Controler.GetProjectConfigNames() if name != old_name]:
@@ -1706,8 +1707,8 @@
                         messageDialog.Destroy()
                     if not abort:
                         self.Controler.ChangeConfigurationName(old_name, new_name)
-                        self.RefreshEditorNames(self.Controler.ComputeConfigurationName(old_name),
-                                                self.Controler.ComputeConfigurationName(new_name))
+                        self.RefreshEditorNames(ComputeConfigurationName(old_name),
+                                                ComputeConfigurationName(new_name))
                         self.RefreshPageTitles()
                 elif item_infos["type"] == ITEM_RESOURCE:
                     if new_name.upper() in [name.upper() for name in self.Controler.GetProjectConfigNames()]:
@@ -1726,8 +1727,8 @@
                     if not abort:
                         words = item_infos["tagname"].split("::")
                         self.Controler.ChangeConfigurationResourceName(words[1], old_name, new_name)
-                        self.RefreshEditorNames(self.Controler.ComputeConfigurationResourceName(words[1], old_name),
-                                                self.Controler.ComputeConfigurationResourceName(words[1], new_name))
+                        self.RefreshEditorNames(ComputeConfigurationResourceName(words[1], old_name),
+                                                ComputeConfigurationResourceName(words[1], new_name))
                         self.RefreshPageTitles()
             if message or abort:
                 if message:
@@ -2465,7 +2466,7 @@
             name = self.ProjectTree.GetItemText(selected)
             if self.CheckDataTypeIsUsedBeforeDeletion(name):
                 self.Controler.ProjectRemoveDataType(name)
-                tagname = self.Controler.ComputeDataTypeName(name)
+                tagname = ComputeDataTypeName(name)
                 idx = self.IsOpened(tagname)
                 if idx is not None:
                     self.TabsOpened.DeletePage(idx)
@@ -2482,7 +2483,7 @@
             name = self.ProjectTree.GetItemText(selected)
             if self.CheckPouIsUsedBeforeDeletion(name):
                 self.Controler.ProjectRemovePou(name)
-                tagname = self.Controler.ComputePouName(name)
+                tagname = ComputePouName(name)
                 idx = self.IsOpened(tagname)
                 if idx is not None:
                     self.TabsOpened.DeletePage(idx)
@@ -2495,7 +2496,7 @@
             transition = self.ProjectTree.GetItemText(selected)
             pou_name = item_infos["tagname"].split("::")[1]
             self.Controler.ProjectRemovePouTransition(pou_name, transition)
-            tagname = self.Controler.ComputePouTransitionName(pou_name, transition)
+            tagname = ComputePouTransitionName(pou_name, transition)
             idx = self.IsOpened(tagname)
             if idx is not None:
                 self.TabsOpened.DeletePage(idx)
@@ -2508,7 +2509,7 @@
             action = self.ProjectTree.GetItemText(selected)
             pou_name = item_infos["tagname"].split("::")[1]
             self.Controler.ProjectRemovePouAction(pou_name, action)
-            tagname = self.Controler.ComputePouActionName(pou_name, action)
+            tagname = ComputePouActionName(pou_name, action)
             idx = self.IsOpened(tagname)
             if idx is not None:
                 self.TabsOpened.DeletePage(idx)
@@ -2519,7 +2520,7 @@
         if self.ProjectTree.GetPyData(selected)["type"] == ITEM_CONFIGURATION:
             name = self.ProjectTree.GetItemText(selected)
             self.Controler.ProjectRemoveConfiguration(name)
-            tagname = self.Controler.ComputeConfigurationName(name)
+            tagname = ComputeConfigurationName(name)
             idx = self.IsOpened(tagname)
             if idx is not None:
                 self.TabsOpened.DeletePage(idx)
@@ -2532,7 +2533,7 @@
             resource = self.ProjectTree.GetItemText(selected)
             config_name = item_infos["tagname"].split("::")[1]
             self.Controler.ProjectRemoveConfigurationResource(config_name, resource)
-            tagname = self.Controler.ComputeConfigurationResourceName(config_name, selected)
+            tagname = ComputeConfigurationResourceName(config_name, selected)
             idx = self.IsOpened(tagname)
             if idx is not None:
                 self.TabsOpened.DeletePage(idx)
@@ -2549,7 +2550,7 @@
             self.RefreshProjectTree()
             self.ProjectTree.Unselect()
         else:
-            self.EditProjectElement(self.Controler.GetElementType(infos[0]), infos[0])
+            self.EditProjectElement(GetElementType(infos[0]), infos[0])
             selected = self.TabsOpened.GetSelection()
             if selected != -1:
                 viewer = self.TabsOpened.GetPage(selected)
--- a/NativeLib.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/NativeLib.py	Fri Mar 02 17:01:25 2018 +0100
@@ -26,9 +26,7 @@
 
 from __future__ import absolute_import
 import util.paths as paths
-from POULibrary import POULibrary
+from POULibrary import SimplePOULibraryFactory
 
-
-class NativeLibrary(POULibrary):
-    def GetLibraryPath(self):
-        return paths.AbsNeighbourFile(__file__, "NativeLib.xml")
+NativeLibrary = SimplePOULibraryFactory(
+    paths.AbsNeighbourFile(__file__, "NativeLib.xml"))
--- a/PLCControler.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/PLCControler.py	Fri Mar 02 17:01:25 2018 +0100
@@ -31,435 +31,23 @@
 import re
 import datetime
 from time import localtime
-from collections import OrderedDict, namedtuple
-
-from lxml import etree
 
 import util.paths as paths
-from util.TranslationCatalogs import NoTranslate
 from plcopen import *
+from plcopen.types_enums import *
+from plcopen.InstancesPathCollector import InstancesPathCollector
+from plcopen.POUVariablesCollector import POUVariablesCollector
+from plcopen.InstanceTagnameCollector import InstanceTagnameCollector
+from plcopen.BlockInstanceCollector import BlockInstanceCollector
+from plcopen.VariableInfoCollector import VariableInfoCollector
 from graphics.GraphicCommons import *
 from PLCGenerator import *
 
 duration_model = re.compile("(?:([0-9]{1,2})h)?(?:([0-9]{1,2})m(?!s))?(?:([0-9]{1,2})s)?(?:([0-9]{1,3}(?:\.[0-9]*)?)ms)?")
 VARIABLE_NAME_SUFFIX_MODEL = re.compile('(\d+)$')
 
-ITEMS_EDITABLE = [
-    ITEM_PROJECT,
-    ITEM_POU,
-    ITEM_VARIABLE,
-    ITEM_TRANSITION,
-    ITEM_ACTION,
-    ITEM_CONFIGURATION,
-    ITEM_RESOURCE,
-    ITEM_DATATYPE
-] = range(8)
-
-ITEMS_UNEDITABLE = [
-    ITEM_DATATYPES,
-    ITEM_FUNCTION,
-    ITEM_FUNCTIONBLOCK,
-    ITEM_PROGRAM,
-    ITEM_TRANSITIONS,
-    ITEM_ACTIONS,
-    ITEM_CONFIGURATIONS,
-    ITEM_RESOURCES,
-    ITEM_PROPERTIES
-] = range(8, 17)
-
-ITEMS_VARIABLE = [
-    ITEM_VAR_LOCAL,
-    ITEM_VAR_GLOBAL,
-    ITEM_VAR_EXTERNAL,
-    ITEM_VAR_TEMP,
-    ITEM_VAR_INPUT,
-    ITEM_VAR_OUTPUT,
-    ITEM_VAR_INOUT
-] = range(17, 24)
-
-VAR_CLASS_INFOS = {
-    "Local":    ("localVars",    ITEM_VAR_LOCAL),
-    "Global":   ("globalVars",   ITEM_VAR_GLOBAL),
-    "External": ("externalVars", ITEM_VAR_EXTERNAL),
-    "Temp":     ("tempVars",     ITEM_VAR_TEMP),
-    "Input":    ("inputVars",    ITEM_VAR_INPUT),
-    "Output":   ("outputVars",   ITEM_VAR_OUTPUT),
-    "InOut":    ("inOutVars",    ITEM_VAR_INOUT)}
-
-POU_TYPES = {
-    "program": ITEM_PROGRAM,
-    "functionBlock": ITEM_FUNCTIONBLOCK,
-    "function": ITEM_FUNCTION,
-}
-
-LOCATIONS_ITEMS = [LOCATION_CONFNODE,
-                   LOCATION_MODULE,
-                   LOCATION_GROUP,
-                   LOCATION_VAR_INPUT,
-                   LOCATION_VAR_OUTPUT,
-                   LOCATION_VAR_MEMORY] = range(6)
-
 ScriptDirectory = paths.AbsDir(__file__)
 
-
-def GetUneditableNames():
-    _ = NoTranslate
-    return [_("User-defined POUs"), _("Functions"), _("Function Blocks"),
-            _("Programs"), _("Data Types"), _("Transitions"), _("Actions"),
-            _("Configurations"), _("Resources"), _("Properties")]
-
-
-UNEDITABLE_NAMES = GetUneditableNames()
-[USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS,
- DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS,
- RESOURCES, PROPERTIES] = UNEDITABLE_NAMES
-
-
-class LibraryResolver(etree.Resolver):
-    """Helper object for loading library in xslt stylesheets"""
-
-    def __init__(self, controller, debug=False):
-        self.Controller = controller
-        self.Debug = debug
-
-    def resolve(self, url, pubid, context):
-        lib_name = os.path.basename(url)
-        if lib_name in ["project", "stdlib", "extensions"]:
-            lib_el = etree.Element(lib_name)
-            if lib_name == "project":
-                lib_el.append(deepcopy(self.Controller.GetProject(self.Debug)))
-            elif lib_name == "stdlib":
-                for lib in StdBlckLibs.values():
-                    lib_el.append(deepcopy(lib))
-            else:
-                for ctn in self.Controller.ConfNodeTypes:
-                    lib_el.append(deepcopy(ctn["types"]))
-            return self.resolve_string(etree.tostring(lib_el), context)
-
-# -------------------------------------------------------------------------------
-#           Helpers functions for translating list of arguments
-#                       from xslt to valid arguments
-# -------------------------------------------------------------------------------
-
-
-def _StringValue(x):
-    return x
-
-
-def _BoolValue(x):
-    return x in ["true", "0"]
-
-
-def _translate_args(translations, args):
-    return [translate(arg[0]) if len(arg) > 0 else None
-            for translate, arg in
-            zip(translations, args)]
-
-# -------------------------------------------------------------------------------
-#                 Helpers object for generating pou var list
-# -------------------------------------------------------------------------------
-
-
-class _VariableInfos(object):
-    __slots__ = ["Name", "Class", "Option", "Location", "InitialValue",
-                 "Edit", "Documentation", "Type", "Tree", "Number"]
-
-    def __init__(self, *args):
-        for attr, value in zip(self.__slots__, args):
-            setattr(self, attr, value if value is not None else "")
-
-    def copy(self):
-        return _VariableInfos(*[getattr(self, attr) for attr in self.__slots__])
-
-
-class VariablesInfosFactory(object):
-
-    def __init__(self, variables):
-        self.Variables = variables
-        self.TreeStack = []
-        self.Type = None
-        self.Dimensions = None
-
-    def SetType(self, context, *args):
-        self.Type = args[0][0]
-
-    def GetType(self):
-        if len(self.Dimensions) > 0:
-            return ("array", self.Type, self.Dimensions)
-        return self.Type
-
-    def GetTree(self):
-        return (self.TreeStack.pop(-1), self.Dimensions)
-
-    def AddDimension(self, context, *args):
-        self.Dimensions.append(tuple(
-            _translate_args([_StringValue] * 2, args)))
-
-    def AddTree(self, context, *args):
-        self.TreeStack.append([])
-        self.Dimensions = []
-
-    def AddVarToTree(self, context, *args):
-        var = (args[0][0], self.Type, self.GetTree())
-        self.TreeStack[-1].append(var)
-
-    def AddVariable(self, context, *args):
-        self.Variables.append(_VariableInfos(*(
-            _translate_args([_StringValue] * 5 + [_BoolValue] + [_StringValue], args) +
-            [self.GetType(), self.GetTree()])))
-
-# -------------------------------------------------------------------------------
-#            Helpers object for generating pou variable instance list
-# -------------------------------------------------------------------------------
-
-
-def class_extraction(value):
-    class_type = {
-        "configuration": ITEM_CONFIGURATION,
-        "resource": ITEM_RESOURCE,
-        "action": ITEM_ACTION,
-        "transition": ITEM_TRANSITION,
-        "program": ITEM_PROGRAM}.get(value)
-    if class_type is not None:
-        return class_type
-
-    pou_type = POU_TYPES.get(value)
-    if pou_type is not None:
-        return pou_type
-
-    var_type = VAR_CLASS_INFOS.get(value)
-    if var_type is not None:
-        return var_type[1]
-
-    return None
-
-
-class _VariablesTreeItemInfos(object):
-    __slots__ = ["name", "var_class", "type", "edit", "debug", "variables"]
-
-    def __init__(self, *args):
-        for attr, value in zip(self.__slots__, args):
-            setattr(self, attr, value if value is not None else "")
-
-    def copy(self):
-        return _VariablesTreeItemInfos(*[getattr(self, attr) for attr in self.__slots__])
-
-
-class VariablesTreeInfosFactory(object):
-
-    def __init__(self):
-        self.Root = None
-
-    def GetRoot(self):
-        return self.Root
-
-    def SetRoot(self, context, *args):
-        self.Root = _VariablesTreeItemInfos(
-            *([''] + _translate_args(
-                [class_extraction, _StringValue] + [_BoolValue] * 2,
-                args) + [[]]))
-
-    def AddVariable(self, context, *args):
-        if self.Root is not None:
-            self.Root.variables.append(_VariablesTreeItemInfos(
-                *(_translate_args(
-                    [_StringValue, class_extraction, _StringValue] +
-                    [_BoolValue] * 2, args) + [[]])))
-
-
-class InstancesPathFactory(object):
-    """Helpers object for generating instances path list"""
-    def __init__(self, instances):
-        self.Instances = instances
-
-    def AddInstance(self, context, *args):
-        self.Instances.append(args[0][0])
-
-
-class InstanceTagName(object):
-    """Helpers object for generating instance tagname"""
-
-    def __init__(self, controller):
-        self.Controller = controller
-        self.TagName = None
-
-    def GetTagName(self):
-        return self.TagName
-
-    def ConfigTagName(self, context, *args):
-        self.TagName = self.Controller.ComputeConfigurationName(args[0][0])
-
-    def ResourceTagName(self, context, *args):
-        self.TagName = self.Controller.ComputeConfigurationResourceName(args[0][0], args[1][0])
-
-    def PouTagName(self, context, *args):
-        self.TagName = self.Controller.ComputePouName(args[0][0])
-
-    def ActionTagName(self, context, *args):
-        self.TagName = self.Controller.ComputePouActionName(args[0][0], args[0][1])
-
-    def TransitionTagName(self, context, *args):
-        self.TagName = self.Controller.ComputePouTransitionName(args[0][0], args[0][1])
-
-
-# -------------------------------------------------------------------------------
-#           Helpers object for generating pou block instances list
-# -------------------------------------------------------------------------------
-
-
-_Point = namedtuple("Point", ["x", "y"])
-
-_BlockInstanceInfos = namedtuple(
-    "BlockInstanceInfos",
-    ["type", "id", "x", "y", "width", "height", "specific_values", "inputs", "outputs"])
-
-_BlockSpecificValues = (
-    namedtuple("BlockSpecificValues",
-               ["name", "execution_order"]),
-    [_StringValue, int])
-_VariableSpecificValues = (
-    namedtuple("VariableSpecificValues",
-               ["name", "value_type", "execution_order"]),
-    [_StringValue, _StringValue, int])
-_ConnectionSpecificValues = (
-    namedtuple("ConnectionSpecificValues", ["name"]),
-    [_StringValue])
-
-_PowerRailSpecificValues = (
-    namedtuple("PowerRailSpecificValues", ["connectors"]),
-    [int])
-
-_LDElementSpecificValues = (
-    namedtuple("LDElementSpecificValues",
-               ["name", "negated", "edge", "storage", "execution_order"]),
-    [_StringValue, _BoolValue, _StringValue, _StringValue, int])
-
-_DivergenceSpecificValues = (
-    namedtuple("DivergenceSpecificValues", ["connectors"]),
-    [int])
-
-_SpecificValuesTuples = {
-    "comment": (
-        namedtuple("CommentSpecificValues", ["content"]),
-        [_StringValue]),
-    "input": _VariableSpecificValues,
-    "output": _VariableSpecificValues,
-    "inout": _VariableSpecificValues,
-    "connector": _ConnectionSpecificValues,
-    "continuation": _ConnectionSpecificValues,
-    "leftPowerRail": _PowerRailSpecificValues,
-    "rightPowerRail": _PowerRailSpecificValues,
-    "contact": _LDElementSpecificValues,
-    "coil": _LDElementSpecificValues,
-    "step": (
-        namedtuple("StepSpecificValues", ["name", "initial", "action"]),
-        [_StringValue, _BoolValue, lambda x: x]),
-    "transition": (
-        namedtuple("TransitionSpecificValues",
-                   ["priority", "condition_type", "condition", "connection"]),
-        [int, _StringValue, _StringValue, lambda x: x]),
-    "selectionDivergence": _DivergenceSpecificValues,
-    "selectionConvergence": _DivergenceSpecificValues,
-    "simultaneousDivergence": _DivergenceSpecificValues,
-    "simultaneousConvergence": _DivergenceSpecificValues,
-    "jump": (
-        namedtuple("JumpSpecificValues", ["target"]),
-        [_StringValue]),
-    "actionBlock": (
-        namedtuple("ActionBlockSpecificValues", ["actions"]),
-        [lambda x: x]),
-}
-
-_InstanceConnectionInfos = namedtuple(
-    "InstanceConnectionInfos",
-    ["name", "negated", "edge", "position", "links"])
-
-_ConnectionLinkInfos = namedtuple(
-    "ConnectionLinkInfos",
-    ["refLocalId", "formalParameter", "points"])
-
-
-class _ActionInfos(object):
-    __slots__ = ["qualifier", "type", "value", "duration", "indicator"]
-
-    def __init__(self, *args):
-        for attr, value in zip(self.__slots__, args):
-            setattr(self, attr, value if value is not None else "")
-
-    def copy(self):
-        return _ActionInfos(*[getattr(self, attr) for attr in self.__slots__])
-
-
-class BlockInstanceFactory(object):
-
-    def __init__(self, block_instances):
-        self.BlockInstances = block_instances
-        self.CurrentInstance = None
-        self.SpecificValues = None
-        self.CurrentConnection = None
-        self.CurrentLink = None
-
-    def SetSpecificValues(self, context, *args):
-        self.SpecificValues = list(args)
-        self.CurrentInstance = None
-        self.CurrentConnection = None
-        self.CurrentLink = None
-
-    def AddBlockInstance(self, context, *args):
-        specific_values_tuple, specific_values_translation = \
-            _SpecificValuesTuples.get(args[0][0], _BlockSpecificValues)
-
-        if args[0][0] == "step" and len(self.SpecificValues) < 3 or \
-           args[0][0] == "transition" and len(self.SpecificValues) < 4:
-            self.SpecificValues.append([None])
-        elif args[0][0] == "actionBlock" and len(self.SpecificValues) < 1:
-            self.SpecificValues.append([[]])
-        specific_values = specific_values_tuple(*_translate_args(
-            specific_values_translation, self.SpecificValues))
-        self.SpecificValues = None
-
-        self.CurrentInstance = _BlockInstanceInfos(
-            *(_translate_args([_StringValue, int] + [float] * 4, args) +
-              [specific_values, [], []]))
-
-        self.BlockInstances[self.CurrentInstance.id] = self.CurrentInstance
-
-    def AddInstanceConnection(self, context, *args):
-        connection_args = _translate_args(
-            [_StringValue] * 2 + [_BoolValue, _StringValue] + [float] * 2, args)
-
-        self.CurrentConnection = _InstanceConnectionInfos(
-            *(connection_args[1:4] + [
-                _Point(*connection_args[4:6]), []]))
-
-        if self.CurrentInstance is not None:
-            if connection_args[0] == "input":
-                self.CurrentInstance.inputs.append(self.CurrentConnection)
-            else:
-                self.CurrentInstance.outputs.append(self.CurrentConnection)
-        else:
-            self.SpecificValues.append([self.CurrentConnection])
-
-    def AddConnectionLink(self, context, *args):
-        self.CurrentLink = _ConnectionLinkInfos(
-            *(_translate_args([int, _StringValue], args) + [[]]))
-        self.CurrentConnection.links.append(self.CurrentLink)
-
-    def AddLinkPoint(self, context, *args):
-        self.CurrentLink.points.append(_Point(
-            *_translate_args([float] * 2, args)))
-
-    def AddAction(self, context, *args):
-        if len(self.SpecificValues) == 0:
-            self.SpecificValues.append([[]])
-        translated_args = _translate_args([_StringValue] * 5, args)
-        self.SpecificValues[0][0].append(_ActionInfos(*translated_args))
-
-
-pou_block_instances_xslt = etree.parse(
-    os.path.join(ScriptDirectory, "plcopen", "pou_block_instances.xslt"))
-
-
 # Length of the buffer
 UNDO_BUFFER_LENGTH = 20
 
@@ -557,6 +145,11 @@
     def __init__(self):
         self.LastNewIndex = 0
         self.Reset()
+        self.InstancesPathCollector = InstancesPathCollector(self)
+        self.POUVariablesCollector = POUVariablesCollector(self)
+        self.InstanceTagnameCollector = InstanceTagnameCollector(self)
+        self.BlockInstanceCollector = BlockInstanceCollector(self)
+        self.VariableInfoCollector = VariableInfoCollector(self)
 
     # Reset PLCControler internal variables
     def Reset(self):
@@ -708,7 +301,7 @@
                 datatypes["values"].append({
                     "name": datatype.getname(),
                     "type": ITEM_DATATYPE,
-                    "tagname": self.ComputeDataTypeName(datatype.getname()),
+                    "tagname": ComputeDataTypeName(datatype.getname()),
                     "values": []})
             pou_types = {
                 "function": {
@@ -730,7 +323,7 @@
             for pou in project.getpous():
                 pou_type = pou.getpouType()
                 pou_infos = {"name": pou.getname(), "type": ITEM_POU,
-                             "tagname": self.ComputePouName(pou.getname())}
+                             "tagname": ComputePouName(pou.getname())}
                 pou_values = []
                 if pou.getbodyType() == "SFC":
                     transitions = []
@@ -738,7 +331,7 @@
                         transitions.append({
                             "name": transition.getname(),
                             "type": ITEM_TRANSITION,
-                            "tagname": self.ComputePouTransitionName(pou.getname(), transition.getname()),
+                            "tagname": ComputePouTransitionName(pou.getname(), transition.getname()),
                             "values": []})
                     pou_values.append({"name": TRANSITIONS, "type": ITEM_TRANSITIONS, "values": transitions})
                     actions = []
@@ -746,7 +339,7 @@
                         actions.append({
                             "name": action.getname(),
                             "type": ITEM_ACTION,
-                            "tagname": self.ComputePouActionName(pou.getname(), action.getname()),
+                            "tagname": ComputePouActionName(pou.getname(), action.getname()),
                             "values": []})
                     pou_values.append({"name": ACTIONS, "type": ITEM_ACTIONS, "values": actions})
                 if pou_type in pou_types:
@@ -758,7 +351,7 @@
                 config_infos = {
                     "name": config_name,
                     "type": ITEM_CONFIGURATION,
-                    "tagname": self.ComputeConfigurationName(config.getname()),
+                    "tagname": ComputeConfigurationName(config.getname()),
                     "values": []}
                 resources = {"name": RESOURCES, "type": ITEM_RESOURCES, "values": []}
                 for resource in config.getresource():
@@ -766,7 +359,7 @@
                     resource_infos = {
                         "name": resource_name,
                         "type": ITEM_RESOURCE,
-                        "tagname": self.ComputeConfigurationResourceName(config.getname(), resource.getname()),
+                        "tagname": ComputeConfigurationResourceName(config.getname(), resource.getname()),
                         "values": []}
                     resources["values"].append(resource_infos)
                 config_infos["values"] = [resources]
@@ -779,18 +372,6 @@
     def GetPouVariables(self, tagname, debug=False):
         project = self.GetProject(debug)
         if project is not None:
-            factory = VariablesTreeInfosFactory()
-
-            parser = etree.XMLParser()
-            parser.resolvers.add(LibraryResolver(self, debug))
-
-            pou_variable_xslt_tree = etree.XSLT(
-                etree.parse(
-                    os.path.join(ScriptDirectory, "plcopen", "pou_variables.xslt"),
-                    parser),
-                extensions={("pou_vars_ns", name): getattr(factory, name)
-                            for name in ["SetRoot", "AddVariable"]})
-
             obj = None
             words = tagname.split("::")
             if words[0] == "P":
@@ -798,31 +379,12 @@
             elif words[0] != "D":
                 obj = self.GetEditedElement(tagname, debug)
             if obj is not None:
-                pou_variable_xslt_tree(obj)
-                return factory.GetRoot()
+                return self.POUVariablesCollector.Collect(obj, debug)
 
         return None
 
     def GetInstanceList(self, root, name, debug=False):
-        instances = []
-        project = self.GetProject(debug)
-        if project is not None:
-            factory = InstancesPathFactory(instances)
-
-            parser = etree.XMLParser()
-            parser.resolvers.add(LibraryResolver(self, debug))
-
-            instances_path_xslt_tree = etree.XSLT(
-                etree.parse(
-                    os.path.join(ScriptDirectory, "plcopen", "instances_path.xslt"),
-                    parser),
-                extensions={
-                    ("instances_ns", "AddInstance"): factory.AddInstance})
-
-            instances_path_xslt_tree(
-                root, instance_type=etree.XSLT.strparam(name))
-
-        return instances
+        return self.InstancesPathCollector.Collect(root, name, debug)
 
     def SearchPouInstances(self, tagname, debug=False):
         project = self.GetProject(debug)
@@ -837,31 +399,15 @@
             elif words[0] in ['T', 'A']:
                 return ["%s.%s" % (instance, words[2])
                         for instance in self.SearchPouInstances(
-                            self.ComputePouName(words[1]), debug)]
+                            ComputePouName(words[1]), debug)]
         return []
 
     def GetPouInstanceTagName(self, instance_path, debug=False):
         project = self.GetProject(debug)
-        factory = InstanceTagName(self)
-
-        parser = etree.XMLParser()
-        parser.resolvers.add(LibraryResolver(self, debug))
-
-        instance_tagname_xslt_tree = etree.XSLT(
-            etree.parse(
-                os.path.join(ScriptDirectory, "plcopen", "instance_tagname.xslt"),
-                parser),
-            extensions={("instance_tagname_ns", name): getattr(factory, name)
-                        for name in ["ConfigTagName",
-                                     "ResourceTagName",
-                                     "PouTagName",
-                                     "ActionTagName",
-                                     "TransitionTagName"]})
-
-        instance_tagname_xslt_tree(
-            project, instance_path=etree.XSLT.strparam(instance_path))
-
-        return factory.GetTagName()
+        if project is not None:
+            return self.InstanceTagnameCollector.Collect(project,
+                                                         debug,
+                                                         instance_path)
 
     def GetInstanceInfos(self, instance_path, debug=False):
         tagname = self.GetPouInstanceTagName(instance_path)
@@ -960,7 +506,7 @@
             # Add the datatype to project
             self.Project.appenddataType(datatype_name)
             self.BufferProject()
-            return self.ComputeDataTypeName(datatype_name)
+            return ComputeDataTypeName(datatype_name)
         return None
 
     # Remove a Data Type from project
@@ -977,7 +523,7 @@
             if pou_type == "function":
                 self.SetPouInterfaceReturnType(pou_name, "BOOL")
             self.BufferProject()
-            return self.ComputePouName(pou_name)
+            return ComputePouName(pou_name)
         return None
 
     def ProjectChangePouType(self, name, pou_type):
@@ -1035,7 +581,7 @@
         self.Project.insertpou(0, new_pou)
         self.BufferProject()
 
-        return self.ComputePouName(new_name),
+        return ComputePouName(new_name),
 
     # Remove a Pou from project
     def ProjectRemovePou(self, pou_name):
@@ -1059,7 +605,7 @@
                 config_name = self.GenerateNewName(None, None, "configuration%d")
             self.Project.addconfiguration(config_name)
             self.BufferProject()
-            return self.ComputeConfigurationName(config_name)
+            return ComputeConfigurationName(config_name)
         return None
 
     # Remove a configuration from project
@@ -1075,7 +621,7 @@
                 resource_name = self.GenerateNewName(None, None, "resource%d")
             self.Project.addconfigurationResource(config_name, resource_name)
             self.BufferProject()
-            return self.ComputeConfigurationResourceName(config_name, resource_name)
+            return ComputeConfigurationResourceName(config_name, resource_name)
         return None
 
     # Remove a resource from a configuration of the project
@@ -1091,7 +637,7 @@
             if pou is not None:
                 pou.addtransition(transition_name, transition_type)
                 self.BufferProject()
-                return self.ComputePouTransitionName(pou_name, transition_name)
+                return ComputePouTransitionName(pou_name, transition_name)
         return None
 
     # Remove a Transition from a Project Pou
@@ -1110,7 +656,7 @@
             if pou is not None:
                 pou.addaction(action_name, action_type)
                 self.BufferProject()
-                return self.ComputePouActionName(pou_name, action_name)
+                return ComputePouActionName(pou_name, action_name)
         return None
 
     # Remove an Action from a Project Pou
@@ -1381,21 +927,8 @@
 
     def GetVariableDictionary(self, object_with_vars, tree=False, debug=False):
         variables = []
-        factory = VariablesInfosFactory(variables)
-
-        parser = etree.XMLParser()
-        parser.resolvers.add(LibraryResolver(self, debug))
-
-        variables_infos_xslt_tree = etree.XSLT(
-            etree.parse(
-                os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt"),
-                parser),
-            extensions={("var_infos_ns", name): getattr(factory, name)
-                        for name in ["SetType", "AddDimension", "AddTree",
-                                     "AddVarToTree", "AddVariable"]})
-        variables_infos_xslt_tree(
-            object_with_vars, tree=etree.XSLT.strparam(str(tree)))
-
+        self.VariableInfoCollector.Collect(object_with_vars,
+                                           debug, variables, tree)
         return variables
 
     # Add a global var to configuration to configuration
@@ -1548,20 +1081,8 @@
             # Return the return type if there is one
             return_type = pou.interface.getreturnType()
             if return_type is not None:
-                factory = VariablesInfosFactory([])
-
-                parser = etree.XMLParser()
-                parser.resolvers.add(LibraryResolver(self))
-
-                return_type_infos_xslt_tree = etree.XSLT(
-                    etree.parse(
-                        os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt"),
-                        parser),
-                    extensions={("var_infos_ns", name): getattr(factory, name)
-                                for name in ["SetType", "AddDimension",
-                                             "AddTree", "AddVarToTree"]})
-                return_type_infos_xslt_tree(
-                    return_type, tree=etree.XSLT.strparam(str(tree)))
+                factory = self.VariableInfoCollector.Collect(return_type,
+                                                             debug, [], tree)
                 if tree:
                     return [factory.GetType(), factory.GetTree()]
                 return factory.GetType()
@@ -1942,45 +1463,6 @@
         return values
 
     # -------------------------------------------------------------------------------
-    #                   Project Element tag name computation functions
-    # -------------------------------------------------------------------------------
-
-    # Compute a data type name
-    def ComputeDataTypeName(self, datatype):
-        return "D::%s" % datatype
-
-    # Compute a pou name
-    def ComputePouName(self, pou):
-        return "P::%s" % pou
-
-    # Compute a pou transition name
-    def ComputePouTransitionName(self, pou, transition):
-        return "T::%s::%s" % (pou, transition)
-
-    # Compute a pou action name
-    def ComputePouActionName(self, pou, action):
-        return "A::%s::%s" % (pou, action)
-
-    # Compute a pou  name
-    def ComputeConfigurationName(self, config):
-        return "C::%s" % config
-
-    # Compute a pou  name
-    def ComputeConfigurationResourceName(self, config, resource):
-        return "R::%s::%s" % (config, resource)
-
-    def GetElementType(self, tagname):
-        words = tagname.split("::")
-        return {
-            "D": ITEM_DATATYPE,
-            "P": ITEM_POU,
-            "T": ITEM_TRANSITION,
-            "A": ITEM_ACTION,
-            "C": ITEM_CONFIGURATION,
-            "R": ITEM_RESOURCE
-        }[words[0]]
-
-    # -------------------------------------------------------------------------------
     #                    Project opened Data types management functions
     # -------------------------------------------------------------------------------
 
@@ -2487,21 +1969,10 @@
             return new_id, connections
 
     def GetEditedElementInstancesInfos(self, tagname, debug=False):
-        element_instances = OrderedDict()
         element = self.GetEditedElement(tagname, debug)
         if element is not None:
-            factory = BlockInstanceFactory(element_instances)
-
-            pou_block_instances_xslt_tree = etree.XSLT(
-                pou_block_instances_xslt,
-                extensions={
-                    ("pou_block_instances_ns", name): getattr(factory, name)
-                    for name in ["AddBlockInstance", "SetSpecificValues",
-                                 "AddInstanceConnection", "AddConnectionLink",
-                                 "AddLinkPoint", "AddAction"]})
-
-            pou_block_instances_xslt_tree(element)
-        return element_instances
+            return self.BlockInstanceCollector.Collect(element, debug)
+        return {}
 
     def ClearEditedElementExecutionOrder(self, tagname):
         element = self.GetEditedElement(tagname)
--- a/PLCGenerator.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/PLCGenerator.py	Fri Mar 02 17:01:25 2018 +0100
@@ -28,6 +28,7 @@
 import re
 from plcopen import PLCOpenParser
 from plcopen.structures import *
+from plcopen.types_enums import *
 
 
 # Dictionary associating PLCOpen variable categories to the corresponding
@@ -134,7 +135,7 @@
 
             # Getting datatype model from project
             datatype = self.Project.getdataType(datatype_name)
-            tagname = self.Controler.ComputeDataTypeName(datatype.getname())
+            tagname = ComputeDataTypeName(datatype.getname())
             datatype_def = [("  ", ()),
                             (datatype.getname(), (tagname, "name")),
                             (" : ", ())]
@@ -268,7 +269,7 @@
 
     # Generate a configuration from its model
     def GenerateConfiguration(self, configuration):
-        tagname = self.Controler.ComputeConfigurationName(configuration.getname())
+        tagname = ComputeConfigurationName(configuration.getname())
         config = [("\nCONFIGURATION ", ()),
                   (configuration.getname(), (tagname, "name")),
                   ("\n", ())]
@@ -342,7 +343,7 @@
 
     # Generate a resource from its model
     def GenerateResource(self, resource, config_name):
-        tagname = self.Controler.ComputeConfigurationResourceName(config_name, resource.getname())
+        tagname = ComputeConfigurationResourceName(config_name, resource.getname())
         resrce = [("\n  RESOURCE ", ()),
                   (resource.getname(), (tagname, "name")),
                   (" ON PLC\n", ())]
@@ -518,7 +519,7 @@
         self.ParentGenerator = parent
         self.Name = name
         self.Type = type
-        self.TagName = self.ParentGenerator.Controler.ComputePouName(name)
+        self.TagName = ComputePouName(name)
         self.CurrentIndent = "  "
         self.ReturnType = None
         self.Interface = []
@@ -578,7 +579,7 @@
                             current_type = var_type
                             break
                 else:
-                    tagname = self.ParentGenerator.Controler.ComputeDataTypeName(current_type)
+                    tagname = ComputeDataTypeName(current_type)
                     infos = self.ParentGenerator.Controler.GetDataTypeInfos(tagname)
                     if infos is not None and infos["type"] == "Structure":
                         name = parts.pop(0)
@@ -841,10 +842,10 @@
             if body_type == "SFC":
                 previous_tagname = self.TagName
                 for action in pou.getactionList():
-                    self.TagName = self.ParentGenerator.Controler.ComputePouActionName(self.Name, action.getname())
+                    self.TagName = ComputePouActionName(self.Name, action.getname())
                     self.ComputeConnectionTypes(action)
                 for transition in pou.gettransitionList():
-                    self.TagName = self.ParentGenerator.Controler.ComputePouTransitionName(self.Name, transition.getname())
+                    self.TagName = ComputePouTransitionName(self.Name, transition.getname())
                     self.ComputeConnectionTypes(transition)
                 self.TagName = previous_tagname
 
@@ -1497,7 +1498,7 @@
             actionContent = pou.getaction(action_name)
             if actionContent is not None:
                 previous_tagname = self.TagName
-                self.TagName = self.ParentGenerator.Controler.ComputePouActionName(self.Name, action_name)
+                self.TagName = ComputePouActionName(self.Name, action_name)
                 self.ComputeProgram(actionContent)
                 self.SFCNetworks["Actions"][action_name] = (self.Program, (self.TagName, "name"))
                 self.Program = []
@@ -1540,7 +1541,7 @@
                 transitionType = transitionContent.getbodyType()
                 transitionBody = transitionContent.getbody()
                 previous_tagname = self.TagName
-                self.TagName = self.ParentGenerator.Controler.ComputePouTransitionName(self.Name, transitionValues["value"])
+                self.TagName = ComputePouTransitionName(self.Name, transitionValues["value"])
                 if transitionType == "IL":
                     transition_infos["content"] = [(":\n", ()),
                                                    (ReIndentText(transitionBody.getcontent().getanyText(), len(self.CurrentIndent)), (self.TagName, "body", len(self.CurrentIndent)))]
--- a/POULibrary.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/POULibrary.py	Fri Mar 02 17:01:25 2018 +0100
@@ -58,3 +58,10 @@
     def Generate_C(self, buildpath, varlist, IECCFLAGS):
         # Pure python or IEC libs doesn't produce C code
         return ((""), [], False), ""
+
+
+def SimplePOULibraryFactory(path):
+    class SimplePOULibrary(POULibrary):
+        def GetLibraryPath(self):
+            return path
+    return SimplePOULibrary
--- a/ProjectController.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/ProjectController.py	Fri Mar 02 17:01:25 2018 +0100
@@ -58,16 +58,15 @@
 from dialogs import DiscoveryDialog
 from PLCControler import PLCControler
 from plcopen.structures import IEC_KEYWORDS
+from plcopen.types_enums import ComputeConfigurationResourceName, ITEM_CONFNODE
 import targets
-from targets.typemapping import DebugTypesSize, UnpackDebugBuffer
+from runtime.typemapping import DebugTypesSize, UnpackDebugBuffer
 from ConfigTreeNode import ConfigTreeNode, XSDSchemaErrorMessage
 
 base_folder = paths.AbsParentDir(__file__)
 
 MATIEC_ERROR_MODEL = re.compile(".*\.st:(\d+)-(\d+)\.\.(\d+)-(\d+): (?:error)|(?:warning) : (.*)$")
 
-ITEM_CONFNODE = 25
-
 
 def ExtractChildrenTypesFromCatalog(catalog):
     children_types = []
@@ -420,7 +419,7 @@
         config = self.Project.getconfiguration(self.GetProjectMainConfigurationName())
         resource = config.getresource()[0].getname()
         config = config.getname()
-        resource_tagname = self.ComputeConfigurationResourceName(config, resource)
+        resource_tagname = ComputeConfigurationResourceName(config, resource)
         def_task = [
             {'Priority': '0', 'Single': '', 'Interval': 'T#20ms', 'Name': 'task0', 'Triggering': 'Cyclic'}]
         def_instance = [
@@ -1808,6 +1807,16 @@
         self._SetConnector(None)
 
     def _Transfer(self):
+        if self.IsPLCStarted():
+            dialog = wx.MessageDialog(
+                self.AppFrame,
+                _("Cannot transfer while PLC is running. Stop it now?"),
+                style=wx.YES_NO | wx.CENTRE)
+            if dialog.ShowModal() == wx.ID_YES:
+                self._Stop()
+            else:
+                return
+
         # Get the last build PLC's
         MD5 = self.GetLastBuildMD5()
 
--- a/canfestival/canfestival.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/canfestival/canfestival.py	Fri Mar 02 17:01:25 2018 +0100
@@ -28,8 +28,8 @@
 import sys
 import shutil
 import wx
-from gnosis.xml.pickle import *
-from gnosis.xml.pickle.util import setParanoia
+from gnosis.xml.pickle import *  # pylint: disable=import-error
+from gnosis.xml.pickle.util import setParanoia  # pylint: disable=import-error
 
 import util.paths as paths
 from util.TranslationCatalogs import AddCatalog
@@ -50,7 +50,7 @@
 from nodemanager import NodeManager
 import gen_cfile
 import eds_utils
-import canfestival_config as local_canfestival_config
+import canfestival_config as local_canfestival_config  # pylint: disable=import-error
 
 from commondialogs import CreateNodeDialog
 from subindextable import IECTypeConversion, SizeConversion
@@ -463,7 +463,9 @@
             raise Exception(res)
 
         file = open(os.path.join(buildpath, "MasterGenerated.od"), "w")
-        dump(master, file)
+        # linter disabled here, undefined variable happens
+        # here because gnosis isn't impored while linting
+        dump(master, file)  # pylint: disable=undefined-variable
         file.close()
 
         return [(Gen_OD_path, local_canfestival_config.getCFLAGS(CanFestivalPath))], "", False
--- a/canfestival/config_utils.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/canfestival/config_utils.py	Fri Mar 02 17:01:25 2018 +0100
@@ -697,7 +697,7 @@
     return pointers
 
 
-if __name__ == "__main__":
+if __name__ == "__main__":  # pylint: disable=all
     def usage():
         print("""
 Usage of config_utils.py test :
--- a/connectors/PYRO/__init__.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/connectors/PYRO/__init__.py	Fri Mar 02 17:01:25 2018 +0100
@@ -76,7 +76,7 @@
 
         def _settimeout(self, timeout):
             self.timeout = timeout
-        from M2Crypto.SSL import Connection
+        from M2Crypto.SSL import Connection  # pylint: disable=import-error
         Connection.timeout = None
         Connection.gettimeout = _gettimeout
         Connection.settimeout = _settimeout
--- a/connectors/WAMP/__init__.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/connectors/WAMP/__init__.py	Fri Mar 02 17:01:25 2018 +0100
@@ -27,7 +27,6 @@
 from __future__ import print_function
 import sys
 import traceback
-import atexit
 from threading import Thread, Event
 
 from twisted.internet import reactor, threads
@@ -83,7 +82,7 @@
 
         # create a WAMP application session factory
         component_config = types.ComponentConfig(
-            realm=realm,
+            realm=unicode(realm),
             extra={"ID": ID})
         session_factory = wamp.ApplicationSessionFactory(
             config=component_config)
@@ -93,9 +92,7 @@
         transport_factory = WampWebSocketClientFactory(
             session_factory,
             url=url,
-            serializers=[MsgPackSerializer()],
-            debug=False,
-            debug_wamp=False)
+            serializers=[MsgPackSerializer()])
 
         # start the client from a Twisted endpoint
         conn = connectWS(transport_factory)
@@ -111,7 +108,7 @@
         reactor.run(installSignalHandlers=False)
 
     def WampSessionProcMapper(funcname):
-        wampfuncname = '.'.join((ID, funcname))
+        wampfuncname = unicode('.'.join((ID, funcname)))
 
         def catcher_func(*args, **kwargs):
             if _WampSession is not None:
--- a/controls/DebugVariablePanel/DebugVariableGraphicViewer.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/controls/DebugVariablePanel/DebugVariableGraphicViewer.py	Fri Mar 02 17:01:25 2018 +0100
@@ -26,7 +26,7 @@
 from __future__ import absolute_import
 from types import TupleType
 from time import time as gettime
-from distutils.version import LooseVersion
+from cycler import cycler
 
 import numpy
 import wx
@@ -42,10 +42,6 @@
 from controls.DebugVariablePanel.GraphButton import GraphButton
 
 
-if LooseVersion(matplotlib.__version__) >= LooseVersion("1.5.0"):
-    from cycler import cycler
-
-
 # Graph variable display type
 GRAPH_PARALLEL, GRAPH_ORTHOGONAL = range(2)
 
@@ -983,10 +979,7 @@
         return AddText
 
     def SetAxesColor(self, color):
-        if LooseVersion(matplotlib.__version__) >= LooseVersion("1.5.0"):
-            self.Axes.set_prop_cycle(cycler('color', color))
-        else:
-            self.Axes.set_color_cycle(color)
+        self.Axes.set_prop_cycle(cycler('color', color))
 
     def ResetGraphics(self):
         """
--- a/controls/LogViewer.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/controls/LogViewer.py	Fri Mar 02 17:01:25 2018 +0100
@@ -33,7 +33,7 @@
 
 from controls.CustomToolTip import CustomToolTip, TOOLTIP_WAIT_PERIOD
 from editors.DebugViewer import DebugViewer, REFRESH_PERIOD
-from targets.typemapping import LogLevelsCount, LogLevels
+from runtime.loglevels import LogLevelsCount, LogLevels
 from util.BitmapLibrary import GetBitmap
 
 
--- a/controls/PouInstanceVariablesPanel.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/controls/PouInstanceVariablesPanel.py	Fri Mar 02 17:01:25 2018 +0100
@@ -30,13 +30,7 @@
 import wx.lib.agw.customtreectrl as CT
 import wx.lib.buttons
 
-from PLCControler import \
-    ITEMS_VARIABLE, \
-    ITEM_CONFIGURATION, \
-    ITEM_RESOURCE, \
-    ITEM_POU, \
-    ITEM_TRANSITION, \
-    ITEM_ACTION
+from plcopen.types_enums import *
 
 from util.BitmapLibrary import GetBitmap
 
@@ -220,7 +214,7 @@
             if tagname == "Project":
                 config_name = self.Controller.GetProjectMainConfigurationName()
                 if config_name is not None:
-                    tagname = self.Controller.ComputeConfigurationName(config_name)
+                    tagname = ComputeConfigurationName(config_name)
             if pou_instance is not None:
                 self.PouInstance = pou_instance
 
@@ -316,20 +310,20 @@
     def EditButtonCallback(self, infos):
         var_class = infos.var_class
         if var_class == ITEM_RESOURCE:
-            tagname = self.Controller.ComputeConfigurationResourceName(
+            tagname = ComputeConfigurationResourceName(
                 self.InstanceChoice.GetStringSelection(),
                 infos.name)
         elif var_class == ITEM_TRANSITION:
-            tagname = self.Controller.ComputePouTransitionName(
+            tagname = ComputePouTransitionName(
                 self.PouTagName.split("::")[1],
                 infos.name)
         elif var_class == ITEM_ACTION:
-            tagname = self.Controller.ComputePouActionName(
+            tagname = ComputePouActionName(
                 self.PouTagName.split("::")[1],
                 infos.name)
         else:
             var_class = ITEM_POU
-            tagname = self.Controller.ComputePouName(infos.type)
+            tagname = ComputePouName(infos.type)
         self.ParentWindow.EditProjectElement(var_class, tagname)
 
     def DebugButtonCallback(self, infos):
@@ -346,21 +340,21 @@
                 self.ParentWindow.OpenDebugViewer(
                     var_class,
                     var_path,
-                    self.Controller.ComputePouTransitionName(
+                    ComputePouTransitionName(
                         self.PouTagName.split("::")[1],
                         infos.name))
             elif var_class == ITEM_ACTION:
                 self.ParentWindow.OpenDebugViewer(
                     var_class,
                     var_path,
-                    self.Controller.ComputePouActionName(
+                    ComputePouActionName(
                         self.PouTagName.split("::")[1],
                         infos.name))
             else:
                 self.ParentWindow.OpenDebugViewer(
                     var_class,
                     var_path,
-                    self.Controller.ComputePouName(infos.type))
+                    ComputePouName(infos.type))
 
     def DebugButtonDClickCallback(self, infos):
         if self.InstanceChoice.GetSelection() != -1:
@@ -420,7 +414,7 @@
                     instance_path = self.InstanceChoice.GetStringSelection()
                     if item_infos.var_class == ITEM_RESOURCE:
                         if instance_path != "":
-                            tagname = self.Controller.ComputeConfigurationResourceName(
+                            tagname = ComputeConfigurationResourceName(
                                 instance_path,
                                 item_infos.name)
                         else:
@@ -428,11 +422,11 @@
                     else:
                         parent_infos = self.VariablesList.GetPyData(selected_item.GetParent())
                         if item_infos.var_class == ITEM_ACTION:
-                            tagname = self.Controller.ComputePouActionName(parent_infos.type, item_infos.name)
+                            tagname = ComputePouActionName(parent_infos.type, item_infos.name)
                         elif item_infos.var_class == ITEM_TRANSITION:
-                            tagname = self.Controller.ComputePouTransitionName(parent_infos.type, item_infos.name)
+                            tagname = ComputePouTransitionName(parent_infos.type, item_infos.name)
                         else:
-                            tagname = self.Controller.ComputePouName(item_infos.type)
+                            tagname = ComputePouName(item_infos.type)
                     if tagname is not None:
                         if instance_path != "":
                             item_path = "%s.%s" % (instance_path, item_infos.name)
--- a/controls/ProjectPropertiesPanel.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/controls/ProjectPropertiesPanel.py	Fri Mar 02 17:01:25 2018 +0100
@@ -25,6 +25,7 @@
 
 from __future__ import absolute_import
 import wx
+from wx.lib.scrolledpanel import ScrolledPanel
 
 from xmlclass.xmlclass import URI_model
 
@@ -76,7 +77,9 @@
 
         # Project Panel elements
 
-        self.ProjectPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL)
+        self.ProjectPanel = ScrolledPanel(self, -1, style=wx.TAB_TRAVERSAL)
+        self.ProjectPanel.SetAutoLayout(1)
+        self.ProjectPanel.SetupScrolling()
         projectpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=5, vgap=15)
         projectpanel_sizer.AddGrowableCol(1)
         self.ProjectPanel.SetSizer(projectpanel_sizer)
@@ -92,7 +95,9 @@
 
         # Author Panel elements
 
-        self.AuthorPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL)
+        self.AuthorPanel = ScrolledPanel(self, -1, style=wx.TAB_TRAVERSAL)
+        self.AuthorPanel.SetAutoLayout(1)
+        self.AuthorPanel.SetupScrolling()
         authorpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=4, vgap=15)
         authorpanel_sizer.AddGrowableCol(1)
         self.AuthorPanel.SetSizer(authorpanel_sizer)
@@ -107,7 +112,9 @@
 
         # Graphics Panel elements
 
-        self.GraphicsPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL)
+        self.GraphicsPanel = ScrolledPanel(self, -1, style=wx.TAB_TRAVERSAL)
+        self.GraphicsPanel.SetAutoLayout(1)
+        self.GraphicsPanel.SetupScrolling()
         graphicpanel_sizer = wx.FlexGridSizer(cols=1, hgap=5, rows=4, vgap=5)
         graphicpanel_sizer.AddGrowableCol(0)
         graphicpanel_sizer.AddGrowableRow(3)
@@ -183,9 +190,13 @@
 
         # Miscellaneous Panel elements
 
-        self.MiscellaneousPanel = wx.Panel(
-            id=-1, parent=self, name='MiscellaneousPanel', pos=wx.Point(0, 0),
-            size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+        self.MiscellaneousPanel = ScrolledPanel(id=-1, parent=self,
+                                                name='MiscellaneousPanel',
+                                                pos=wx.Point(0, 0),
+                                                size=wx.Size(0, 0),
+                                                style=wx.TAB_TRAVERSAL)
+        self.MiscellaneousPanel.SetAutoLayout(1)
+        self.MiscellaneousPanel.SetupScrolling()
         miscellaneouspanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=15)
         miscellaneouspanel_sizer.AddGrowableCol(1)
         miscellaneouspanel_sizer.AddGrowableRow(1)
--- a/controls/SearchResultPanel.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/controls/SearchResultPanel.py	Fri Mar 02 17:01:25 2018 +0100
@@ -32,6 +32,7 @@
 
 from PLCControler import *
 from util.BitmapLibrary import GetBitmap
+from plcopen.types_enums import GetElementType
 
 
 def GenerateName(infos):
@@ -196,7 +197,7 @@
 
                 words = tagname.split("::")
 
-                element_type = self.ParentWindow.Controler.GetElementType(tagname)
+                element_type = GetElementType(tagname)
                 if element_type == ITEM_POU:
                     element_type = self.ParentWindow.Controler.GetPouType(words[1])
 
--- a/controls/VariablePanel.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/controls/VariablePanel.py	Fri Mar 02 17:01:25 2018 +0100
@@ -32,6 +32,7 @@
 import wx.lib.buttons
 
 from plcopen.structures import LOCATIONDATATYPES, TestIdentifier, IEC_KEYWORDS, DefaultType
+from plcopen.VariableInfoCollector import _VariableInfos
 from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD, ERROR_HIGHLIGHT
 from dialogs.ArrayTypeDialog import ArrayTypeDialog
 from controls.CustomGrid import CustomGrid
@@ -39,7 +40,6 @@
 from controls.LocationCellEditor import LocationCellEditor
 from util.BitmapLibrary import GetBitmap
 from util.TranslationCatalogs import NoTranslate
-from PLCControler import _VariableInfos
 
 
 # -------------------------------------------------------------------------------
--- a/dialogs/ActionBlockDialog.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/dialogs/ActionBlockDialog.py	Fri Mar 02 17:01:25 2018 +0100
@@ -29,7 +29,7 @@
 import wx.lib.buttons
 
 from controls import CustomGrid, CustomTable
-from PLCControler import _ActionInfos
+from plcopen.BlockInstanceCollector import _ActionInfos
 from util.BitmapLibrary import GetBitmap
 from util.TranslationCatalogs import NoTranslate
 # -------------------------------------------------------------------------------
--- a/editors/ProjectNodeEditor.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/editors/ProjectNodeEditor.py	Fri Mar 02 17:01:25 2018 +0100
@@ -28,6 +28,7 @@
 
 from controls import ProjectPropertiesPanel, VariablePanel
 from editors.ConfTreeNodeEditor import ConfTreeNodeEditor
+from plcopen.types_enums import ComputeConfigurationName
 
 
 class ProjectNodeEditor(ConfTreeNodeEditor):
@@ -52,7 +53,7 @@
     def __init__(self, parent, controler, window):
         configuration = controler.GetProjectMainConfigurationName()
         if configuration is not None:
-            tagname = controler.ComputeConfigurationName(configuration)
+            tagname = ComputeConfigurationName(configuration)
         else:
             tagname = ""
 
--- a/editors/TextViewer.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/editors/TextViewer.py	Fri Mar 02 17:01:25 2018 +0100
@@ -424,7 +424,6 @@
     def RefreshJumpList(self):
         if self.TextSyntax == "IL":
             self.Jumps = [jump.upper() for jump in LABEL_MODEL.findall(self.GetText())]
-            self.Colourise(0, -1)
 
     # Buffer the last model state
     def RefreshBuffer(self):
@@ -848,6 +847,7 @@
 
     def RefreshModel(self):
         self.RefreshJumpList()
+        self.Colourise(0, -1)
         self.Controler.SetEditedElementText(self.TagName, self.GetText())
         self.ResetSearchResults()
 
--- a/editors/Viewer.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/editors/Viewer.py	Fri Mar 02 17:01:25 2018 +0100
@@ -32,9 +32,16 @@
 import wx
 
 from plcopen.structures import *
+from plcopen.types_enums import ComputePouName
 from PLCControler import ITEM_VAR_LOCAL, ITEM_POU, ITEM_PROGRAM, ITEM_FUNCTIONBLOCK
+
+from graphics.GraphicCommons import *
+from graphics.FBD_Objects import *
+from graphics.LD_Objects import *
+from graphics.SFC_Objects import *
+from graphics.RubberBand import RubberBand
 from graphics.DebugDataConsumer import DebugDataConsumer
-from graphics import *
+
 from dialogs import *
 from editors.DebugViewer import DebugViewer, REFRESH_PERIOD
 from editors.EditorPanel import EditorPanel
@@ -2278,7 +2285,7 @@
                             self.ParentWindow.OpenDebugViewer(
                                 pou_type,
                                 "%s.%s" % (self.GetInstancePath(True), self.SelectedElement.GetName()),
-                                self.Controler.ComputePouName(instance_type))
+                                ComputePouName(instance_type))
                 else:
                     iec_path = self.GetElementIECPath(self.SelectedElement)
                     if iec_path is not None:
@@ -2298,7 +2305,7 @@
                     if instance_type in self.Controler.GetProjectPouNames(self.Debug):
                         self.ParentWindow.EditProjectElement(
                             ITEM_POU,
-                            self.Controler.ComputePouName(instance_type))
+                            ComputePouName(instance_type))
                     else:
                         self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling)
             elif event.ControlDown() and event.ShiftDown():
--- a/features.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/features.py	Fri Mar 02 17:01:25 2018 +0100
@@ -29,6 +29,7 @@
 
 catalog = [
     ('canfestival', _('CANopen support'), _('Map located variables over CANopen'), 'canfestival.canfestival.RootClass'),
+    ('modbus', _('Modbus support'), _('Map located variables over Modbus'), 'modbus.modbus.RootClass'),
     ('c_ext', _('C extension'), _('Add C code accessing located variables synchronously'), 'c_ext.CFile'),
     ('py_ext', _('Python file'), _('Add Python code executed asynchronously'), 'py_ext.PythonFile'),
     ('wxglade_hmi', _('WxGlade GUI'), _('Add a simple WxGlade based GUI.'), 'wxglade_hmi.WxGladeHMI'),
--- a/graphics/__init__.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/graphics/__init__.py	Fri Mar 02 17:01:25 2018 +0100
@@ -23,12 +23,3 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 # Package initialisation
-
-from __future__ import absolute_import
-
-from graphics.GraphicCommons import *
-from graphics.FBD_Objects import *
-from graphics.LD_Objects import *
-from graphics.SFC_Objects import *
-from graphics.RubberBand import RubberBand
-from graphics.DebugDataConsumer import DebugDataConsumer
--- a/i18n/mki18n.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/i18n/mki18n.py	Fri Mar 02 17:01:25 2018 +0100
@@ -439,7 +439,8 @@
 # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 #
 if __name__ == "__main__":
-    import getopt     # command line parsing
+    # command line parsing
+    import getopt    # pylint: disable=wrong-import-order,wrong-import-position
     argc = len(sys.argv)
     if argc == 1:
         printUsage('Missing argument: specify at least one of -m or -p (or both).')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modbus/README	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,1 @@
+Modbus
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modbus/__init__.py	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# This file is part of Beremiz, a Integrated Development Environment for
+# programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
+#
+# Copyright (c) 2016 Mario de Sousa (msousa@fe.up.pt)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# This code is made available on the understanding that it will not be
+# used in safety-critical situations without a full and competent review.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modbus/mb_runtime.c	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,603 @@
+/* File generated by Beremiz (PlugGenerate_C method of Modbus plugin) */
+
+/*
+ * Copyright (c) 2016 Mario de Sousa (msousa@fe.up.pt)
+ *
+ * This file is part of the Modbus library for Beremiz and matiec.
+ *
+ * This Modbus library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this Modbus library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This code is made available on the understanding that it will not be
+ * used in safety-critical situations without a full and competent review.
+ */
+
+
+#include <stdio.h>
+#include <string.h>  /* required for memcpy() */
+#include "mb_slave_and_master.h"
+#include "MB_%(locstr)s.h"
+
+
+#define MAX_MODBUS_ERROR_CODE 11
+static const char *modbus_error_messages[MAX_MODBUS_ERROR_CODE+1] = {
+    /* 0 */ "",                             /* un-used -> no error! */
+    /* 1 */ "illegal/unsuported function",
+    /* 2 */ "illegal data address",
+    /* 3 */ "illegal data value",
+    /* 4 */ "slave device failure",
+    /* 5 */ "acknowledge -> slave intends to reply later",
+    /* 6 */ "slave device busy",
+    /* 7 */ "negative acknowledge",
+    /* 8 */ "memory parity error",
+    /* 9 */ "",                             /* undefined by Modbus */
+    /* 10*/ "gateway path unavalilable",
+    /* 11*/ "gateway target device failed to respond"
+};    
+
+
+/* Execute a modbus client transaction/request */
+static int __execute_mb_request(int request_id){
+	switch (client_requests[request_id].mb_function){
+	
+	case  1: /* read coils */
+		return read_output_bits(client_requests[request_id].slave_id,
+					client_requests[request_id].address,
+					client_requests[request_id].count,
+					client_requests[request_id].coms_buffer,
+					(int) client_requests[request_id].count,
+					client_nodes[client_requests[request_id].client_node_id].mb_nd,
+					client_requests[request_id].retries,
+					&(client_requests[request_id].error_code),
+					&(client_requests[request_id].resp_timeout),
+					&(client_requests[request_id].coms_buf_mutex));
+
+	case  2: /* read discrete inputs */
+		return read_input_bits( client_requests[request_id].slave_id,
+					client_requests[request_id].address,
+					client_requests[request_id].count,
+					client_requests[request_id].coms_buffer,
+					(int) client_requests[request_id].count,
+					client_nodes[client_requests[request_id].client_node_id].mb_nd,
+					client_requests[request_id].retries,
+					&(client_requests[request_id].error_code),
+					&(client_requests[request_id].resp_timeout),
+					&(client_requests[request_id].coms_buf_mutex));
+
+	case  3: /* read holding registers */
+		return read_output_words(client_requests[request_id].slave_id,
+					client_requests[request_id].address,
+					client_requests[request_id].count,
+					client_requests[request_id].coms_buffer,
+					(int) client_requests[request_id].count,
+					client_nodes[client_requests[request_id].client_node_id].mb_nd,
+					client_requests[request_id].retries,
+					&(client_requests[request_id].error_code),
+					&(client_requests[request_id].resp_timeout),
+					&(client_requests[request_id].coms_buf_mutex));
+	
+	case  4: /* read input registers */
+		return read_input_words(client_requests[request_id].slave_id,
+					client_requests[request_id].address,
+					client_requests[request_id].count,
+					client_requests[request_id].coms_buffer,
+					(int) client_requests[request_id].count,
+					client_nodes[client_requests[request_id].client_node_id].mb_nd,
+					client_requests[request_id].retries,
+					&(client_requests[request_id].error_code),
+					&(client_requests[request_id].resp_timeout),
+					&(client_requests[request_id].coms_buf_mutex));
+
+	case  5: /* write single coil */
+		return write_output_bit(client_requests[request_id].slave_id,
+					client_requests[request_id].address,
+					client_requests[request_id].coms_buffer[0],
+					client_nodes[client_requests[request_id].client_node_id].mb_nd,
+					client_requests[request_id].retries,
+					&(client_requests[request_id].error_code),
+					&(client_requests[request_id].resp_timeout),
+					&(client_requests[request_id].coms_buf_mutex));
+
+	case  6: /* write single register */
+		return write_output_word(client_requests[request_id].slave_id,
+					client_requests[request_id].address,
+					client_requests[request_id].coms_buffer[0],
+					client_nodes[client_requests[request_id].client_node_id].mb_nd,
+					client_requests[request_id].retries,
+					&(client_requests[request_id].error_code),
+					&(client_requests[request_id].resp_timeout),
+					&(client_requests[request_id].coms_buf_mutex));
+
+	case  7: break; /* function not yet supported */
+	case  8: break; /* function not yet supported */
+	case  9: break; /* function not yet supported */
+	case 10: break; /* function not yet supported */
+	case 11: break; /* function not yet supported */
+	case 12: break; /* function not yet supported */
+	case 13: break; /* function not yet supported */
+	case 14: break; /* function not yet supported */
+	
+	case 15: /* write multiple coils */
+		return write_output_bits(client_requests[request_id].slave_id,
+					 client_requests[request_id].address,
+					 client_requests[request_id].count,
+					 client_requests[request_id].coms_buffer,
+					 client_nodes[client_requests[request_id].client_node_id].mb_nd,
+					 client_requests[request_id].retries,
+					 &(client_requests[request_id].error_code),
+					 &(client_requests[request_id].resp_timeout),
+					 &(client_requests[request_id].coms_buf_mutex));
+
+	case 16: /* write multiple registers */
+		return write_output_words(client_requests[request_id].slave_id,
+					client_requests[request_id].address,
+					client_requests[request_id].count,
+					client_requests[request_id].coms_buffer,
+					client_nodes[client_requests[request_id].client_node_id].mb_nd,
+					client_requests[request_id].retries,
+					&(client_requests[request_id].error_code),
+					&(client_requests[request_id].resp_timeout),
+					&(client_requests[request_id].coms_buf_mutex));
+	
+	default: break;  /* should never occur, if file generation is correct */
+	}
+
+	fprintf(stderr, "Modbus plugin: Modbus function %%d not supported\n", request_id); /* should never occur, if file generation is correct */
+	return -1;
+}
+
+
+
+/* pack bits from unpacked_data to packed_data */
+static inline int __pack_bits(u16 *unpacked_data, u16 start_addr, u16 bit_count,  u8  *packed_data) {
+  u8 bit;
+  u16 byte, coils_processed;
+
+  if ((0 == bit_count) || (65535-start_addr < bit_count-1))
+    return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */
+  
+  for( byte = 0, coils_processed = 0; coils_processed < bit_count; byte++) {
+    packed_data[byte] = 0;
+    for( bit = 0x01; (bit & 0xFF) && (coils_processed < bit_count); bit <<= 1, coils_processed++ ) {
+      if(unpacked_data[start_addr + coils_processed])
+            packed_data[byte] |=  bit; /*   set bit */
+      else  packed_data[byte] &= ~bit; /* reset bit */
+    }
+  }
+  return 0;
+}
+
+
+/* unpack bits from packed_data to unpacked_data */
+static inline int __unpack_bits(u16 *unpacked_data, u16 start_addr, u16 bit_count,  u8  *packed_data) {
+  u8  temp, bit;
+  u16 byte, coils_processed;
+
+  if ((0 == bit_count) || (65535-start_addr < bit_count-1))
+    return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */
+  
+  for(byte = 0, coils_processed = 0; coils_processed < bit_count; byte++) {
+    temp = packed_data[byte] ;
+    for(bit = 0x01; (bit & 0xff) && (coils_processed < bit_count); bit <<= 1, coils_processed++) {
+      unpacked_data[start_addr + coils_processed] = (temp & bit)?1:0;
+    }
+  }
+  return 0;
+}
+
+
+static int __read_inbits   (void *mem_map, u16 start_addr, u16 bit_count, u8  *data_bytes)
+  {return   __pack_bits(((server_mem_t *)mem_map)->ro_bits, start_addr, bit_count, data_bytes);}
+static int __read_outbits  (void *mem_map, u16 start_addr, u16 bit_count, u8  *data_bytes)
+  {return   __pack_bits(((server_mem_t *)mem_map)->rw_bits, start_addr, bit_count, data_bytes);}
+static int __write_outbits (void *mem_map, u16 start_addr, u16 bit_count, u8  *data_bytes)
+  {return __unpack_bits(((server_mem_t *)mem_map)->rw_bits, start_addr, bit_count, data_bytes); }
+
+
+
+static int __read_inwords  (void *mem_map, u16 start_addr, u16 word_count, u16 *data_words) {
+
+  if ((start_addr + word_count) > MEM_AREA_SIZE)
+    return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */
+
+  /* use memcpy() because loop with pointers (u16 *) caused alignment problems */
+  memcpy(/* dest */ (void *)data_words,
+         /* src  */ (void *)&(((server_mem_t *)mem_map)->ro_words[start_addr]),
+         /* size */ word_count * 2);
+  return 0;
+}
+
+
+
+static int __read_outwords (void *mem_map, u16 start_addr, u16 word_count, u16 *data_words) {
+
+  if ((start_addr + word_count) > MEM_AREA_SIZE)
+    return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */
+
+  /* use memcpy() because loop with pointers (u16 *) caused alignment problems */
+  memcpy(/* dest */ (void *)data_words,
+         /* src  */ (void *)&(((server_mem_t *)mem_map)->rw_words[start_addr]),
+         /* size */ word_count * 2);
+  return 0;
+}
+
+
+
+
+static int __write_outwords(void *mem_map, u16 start_addr, u16 word_count, u16 *data_words) {
+
+  if ((start_addr + word_count) > MEM_AREA_SIZE)
+    return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */
+
+  /* WARNING: The data returned in the data_words[] array is not guaranteed to be 16 bit aligned.
+   *           It is not therefore safe to cast it to an u16 data type.
+   *           The following code cannot be used. memcpy() is used instead.
+   */
+  /*
+  for (count = 0; count < word_count ; count++)
+    ((server_mem_t *)mem_map)->rw_words[count + start_addr] = data_words[count];
+  */
+  memcpy(/* dest */ (void *)&(((server_mem_t *)mem_map)->rw_words[start_addr]),
+         /* src  */ (void *)data_words,
+         /* size */ word_count * 2);
+  return 0;
+}
+
+
+
+
+#include <pthread.h>
+
+static void *__mb_server_thread(void *_server_node)  {
+	server_node_t *server_node = _server_node;
+	mb_slave_callback_t callbacks = { 
+			&__read_inbits,
+			&__read_outbits,
+			&__write_outbits,
+			&__read_inwords,
+			&__read_outwords,
+			&__write_outwords,
+			(void *)&(server_node->mem_area)
+			};  
+	
+	// Enable thread cancelation. Enabled is default, but set it anyway to be safe.
+	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+	// mb_slave_run() should never return!
+	mb_slave_run(server_node->mb_nd /* nd */, callbacks, server_node->slave_id);
+	fprintf(stderr, "Modbus plugin: Modbus server for node %%s died unexpectedly!\n", server_node->location); /* should never occur */
+	return NULL;
+}
+
+
+
+static void *__mb_client_thread(void *_index)  {
+	int client_node_id = (char *)_index - (char *)NULL; // Use pointer arithmetic (more portable than cast)
+	struct timespec next_cycle;
+	int period_sec  =  client_nodes[client_node_id].comm_period / 1000;          /* comm_period is in ms */
+	int period_nsec = (client_nodes[client_node_id].comm_period %%1000)*1000000; /* comm_period is in ms */
+
+	// Enable thread cancelation. Enabled is default, but set it anyway to be safe.
+	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+	
+	// get the current time
+	clock_gettime(CLOCK_MONOTONIC, &next_cycle);
+
+	// loop the communication with the client
+	while (1) {
+		/*
+		struct timespec cur_time;
+		clock_gettime(CLOCK_MONOTONIC, &cur_time);
+		fprintf(stderr, "Modbus client thread - new cycle (%%ld:%%ld)!\n", cur_time.tv_sec, cur_time.tv_nsec);
+		*/
+		int req;
+		for (req=0; req < NUMBER_OF_CLIENT_REQTS; req ++){
+			/*just do the requests belonging to the client */
+			if (client_requests[req].client_node_id != client_node_id)
+				continue;
+			int res_tmp = __execute_mb_request(req);
+			switch (res_tmp) {
+			  case PORT_FAILURE: {
+				if (res_tmp != client_nodes[client_node_id].prev_error)
+					fprintf(stderr, "Modbus plugin: Error connecting Modbus client %%s to remote server.\n", client_nodes[client_node_id].location);
+				client_nodes[client_node_id].prev_error = res_tmp;
+				break;
+			  }
+			  case INVALID_FRAME: {
+				if ((res_tmp != client_requests[req].prev_error) && (0 == client_nodes[client_node_id].prev_error))
+					fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s was unsuccesful. Server/slave returned an invalid/corrupted frame.\n", client_requests[req].location);
+				client_requests[req].prev_error = res_tmp;
+				break;
+			  }
+			  case TIMEOUT: {
+				if ((res_tmp != client_requests[req].prev_error) && (0 == client_nodes[client_node_id].prev_error))
+					fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s timed out waiting for reply from server.\n", client_requests[req].location);
+				client_requests[req].prev_error = res_tmp;
+				break;
+			  }
+			  case MODBUS_ERROR: {
+				if (client_requests[req].prev_error != client_requests[req].error_code) {
+					fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s was unsuccesful. Server/slave returned error code 0x%%2x", client_requests[req].location, client_requests[req].error_code);
+					if (client_requests[req].error_code <= MAX_MODBUS_ERROR_CODE ) {
+						fprintf(stderr, "(%%s)", modbus_error_messages[client_requests[req].error_code]);
+						fprintf(stderr, ".\n");
+					}
+				}
+				client_requests[req].prev_error = client_requests[req].error_code;
+				break;
+			  }
+			  default: {
+				if ((res_tmp >= 0) && (client_nodes[client_node_id].prev_error != 0)) {
+					fprintf(stderr, "Modbus plugin: Modbus client %%s has reconnected to server/slave.\n", client_nodes[client_node_id].location);
+				}
+				if ((res_tmp >= 0) && (client_requests[req]        .prev_error != 0)) {
+					fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s has succesfully resumed comunication.\n", client_requests[req].location);
+				}
+				client_nodes[client_node_id].prev_error = 0;
+				client_requests[req]        .prev_error = 0;
+				break;
+			  }
+			}
+		}
+		// Determine absolute time instant for starting the next cycle
+		// struct timespec prev_cycle;
+		// prev_cycle = next_cycle;
+		next_cycle.tv_sec  += period_sec;
+		next_cycle.tv_nsec += period_nsec;
+		if (next_cycle.tv_nsec >= 1000000000) {
+			next_cycle.tv_sec  ++;
+			next_cycle.tv_nsec -= 1000000000;
+		}
+		/* It probably does not make sense to check for overflow of timer.
+		 * Even in 32 bit systems this will take at least 68 years since the computer booted
+		 * (remember, we are using CLOCK_MONOTONIC, which should start counting from 0
+		 * every time the system boots). On 64 bit systems, it will take over 
+		 * 10^11 years to overflow.
+		 */
+		/*
+		if (next_cycle.tv_sec) < prev_cycle.tv_sec) {
+			// we will lose some precision by reading the time again, 
+			// but it is better than the alternative...
+			clock_gettime(CLOCK_MONOTONIC, &next_cycle);
+			next_cycle.tv_sec  += period_sec;
+			next_cycle.tv_nsec += period_nsec;
+			if (next_cycle.tv_nsec >= 1000000000) {
+				next_cycle.tv_sec  ++;
+				next_cycle.tv_nsec -= 1000000000;
+			}
+		}
+		*/
+		clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_cycle, NULL);
+	}
+
+	// humour the compiler.
+	return NULL;
+}
+
+
+int __cleanup_%(locstr)s ();
+int __init_%(locstr)s (int argc, char **argv){
+	int index;
+
+	for (index=0; index < NUMBER_OF_CLIENT_NODES;index++)
+		client_nodes[index].mb_nd = -1;
+	for (index=0; index < NUMBER_OF_SERVER_NODES;index++)
+		// mb_nd with negative numbers indicate how far it has been initialised (or not)
+		//   -2  --> no modbus node created;  no thread  created
+		//   -1  -->    modbus node created!; no thread  created
+		//  >=0  -->    modbus node created!;    thread  created!
+		server_nodes[index].mb_nd = -2; 
+
+	/* modbus library init */
+	/* Note that TOTAL_xxxNODE_COUNT are the nodes required by _ALL_ the instances of the modbus
+	 *  extension currently in the user's project. This file (MB_xx.c) is handling only one instance,
+	 *  but must initialize the library for all instances. Only the first call to mb_slave_and_master_init()
+	 *  will result in memory being allocated. All subsequent calls (by other MB_xx,c files) will be ignored
+	 *  by the mb_slave_and_master_init() funtion, as long as they are called with the same arguments.
+	 */
+	if (mb_slave_and_master_init(TOTAL_TCPNODE_COUNT, TOTAL_RTUNODE_COUNT, TOTAL_ASCNODE_COUNT) <0) {
+		fprintf(stderr, "Modbus plugin: Error starting modbus library\n");
+		// return imediately. Do NOT goto error_exit, as we did not get to
+		//  start the modbus library!
+		return -1;
+	}
+	
+	/* init the mutex for each client request */
+	/* Must be done _before_ launching the client threads!! */
+	for (index=0; index < NUMBER_OF_CLIENT_REQTS; index ++){
+		if (pthread_mutex_init(&(client_requests[index].coms_buf_mutex), NULL)) {
+			fprintf(stderr, "Modbus plugin: Error initializing request for modbus client node %%s\n", client_nodes[client_requests[index].client_node_id].location);
+			goto error_exit;
+		}
+	}
+
+	/* init each client connection to remote modbus server, and launch thread */
+	/* NOTE: All client_nodes[].init_state are initialised to 0 in the code 
+	 *       generated by the modbus plugin 
+	 */
+	for (index=0; index < NUMBER_OF_CLIENT_NODES;index++){
+		/* establish client connection */
+		client_nodes[index].mb_nd = mb_master_connect (client_nodes[index].node_address);
+		if (client_nodes[index].mb_nd < 0){
+			fprintf(stderr, "Modbus plugin: Error creating modbus client node %%s\n", client_nodes[index].location);
+			goto error_exit;
+		}
+		client_nodes[index].init_state = 1; // we have created the node 
+		
+		/* launch a thread to handle this client node */
+		{
+			int res = 0;
+			pthread_attr_t attr;
+			res |= pthread_attr_init(&attr);
+			res |= pthread_create(&(client_nodes[index].thread_id), &attr, &__mb_client_thread, (void *)((char *)NULL + index));
+			if (res !=  0) {
+				fprintf(stderr, "Modbus plugin: Error starting modbus client thread for node %%s\n", client_nodes[index].location);
+				goto error_exit;
+			}
+		}
+		client_nodes[index].init_state = 2; // we have created the node and a thread
+	}
+
+	/* init each local server */
+	/* NOTE: All server_nodes[].init_state are initialised to 0 in the code 
+	 *       generated by the modbus plugin 
+	 */
+	for (index=0; index < NUMBER_OF_SERVER_NODES;index++){
+		/* create the modbus server */
+		server_nodes[index].mb_nd = mb_slave_new (server_nodes[index].node_address);
+		if (server_nodes[index].mb_nd < 0){
+			fprintf(stderr, "Modbus plugin: Error creating modbus server node %%s\n", server_nodes[index].location);
+			goto error_exit;
+		}
+		server_nodes[index].init_state = 1; // we have created the node
+		
+		/* launch a thread to handle this server node */
+		{
+			int res = 0;
+			pthread_attr_t attr;
+			res |= pthread_attr_init(&attr);
+			res |= pthread_create(&(server_nodes[index].thread_id), &attr, &__mb_server_thread, (void *)&(server_nodes[index]));
+			if (res !=  0) {
+				fprintf(stderr, "Modbus plugin: Error starting modbus server thread for node %%s\n", server_nodes[index].location);
+				goto error_exit;
+			}
+		}
+		server_nodes[index].init_state = 2; // we have created the node and thread
+	}
+
+	return 0;
+	
+error_exit:
+	__cleanup_%(locstr)s ();
+	return -1;
+}
+
+
+
+
+
+void __publish_%(locstr)s (){
+	int index;
+
+	for (index=0; index < NUMBER_OF_CLIENT_REQTS; index ++){
+		/*just do the output requests */
+		if (client_requests[index].req_type == req_output){
+			pthread_mutex_lock(&(client_requests[index].coms_buf_mutex));
+			// copy from plcv_buffer to coms_buffer
+			memcpy((void *)client_requests[index].coms_buffer /* destination */,
+			       (void *)client_requests[index].plcv_buffer /* source */,
+			       REQ_BUF_SIZE * sizeof(u16) /* size in bytes */);
+			pthread_mutex_unlock(&(client_requests[index].coms_buf_mutex));
+		}
+	}
+}
+
+
+
+
+
+void __retrieve_%(locstr)s (){
+	int index;
+
+	for (index=0; index < NUMBER_OF_CLIENT_REQTS; index ++){
+		/*just do the input requests */
+		if (client_requests[index].req_type == req_input){
+			pthread_mutex_lock(&(client_requests[index].coms_buf_mutex));
+			// copy from coms_buffer to plcv_buffer
+			memcpy((void *)client_requests[index].plcv_buffer /* destination */,
+			       (void *)client_requests[index].coms_buffer /* source */,
+			       REQ_BUF_SIZE * sizeof(u16) /* size in bytes */);
+			pthread_mutex_unlock(&(client_requests[index].coms_buf_mutex));
+		}
+	}
+}
+
+
+
+
+
+int __cleanup_%(locstr)s (){
+	int index, close;
+	int res = 0;
+
+	/* kill thread and close connections of each modbus client node */
+	for (index=0; index < NUMBER_OF_CLIENT_NODES; index++) {
+		close = 0;
+		if (client_nodes[index].init_state >= 2) {
+			// thread was launched, so we try to cancel it!
+			close  = pthread_cancel(client_nodes[index].thread_id);
+			close |= pthread_join  (client_nodes[index].thread_id, NULL);
+			if (close < 0)
+				fprintf(stderr, "Modbus plugin: Error closing thread for modbus client %%s\n", client_nodes[index].location);
+		}
+		res |= close;
+
+		close = 0;
+		if (client_nodes[index].init_state >= 1) {
+			// modbus client node was created, so we try to close it!
+			close = mb_master_close (client_nodes[index].mb_nd);
+			if (close < 0){
+				fprintf(stderr, "Modbus plugin: Error closing modbus client node %%s\n", client_nodes[index].location);
+				// We try to shut down as much as possible, so we do not return noW!
+			}
+			client_nodes[index].mb_nd = -1;
+		}
+		res |= close;
+		client_nodes[index].init_state = 0;
+	}
+	
+	/* kill thread and close connections of each modbus server node */
+	for (index=0; index < NUMBER_OF_SERVER_NODES; index++) {
+		close = 0;
+		if (server_nodes[index].init_state >= 2) {
+			// thread was launched, so we try to cancel it!
+			close  = pthread_cancel(server_nodes[index].thread_id);
+			close |= pthread_join  (server_nodes[index].thread_id, NULL);
+			if (close < 0)
+				fprintf(stderr, "Modbus plugin: Error closing thread for modbus server %%s\n", server_nodes[index].location);
+		}
+		res |= close;
+
+		close = 0;
+		if (server_nodes[index].init_state >= 1) {
+			// modbus server node was created, so we try to close it!
+			close = mb_slave_close (server_nodes[index].mb_nd);
+			if (close < 0) {
+				fprintf(stderr, "Modbus plugin: Error closing node for modbus server %%s (%%d)\n", server_nodes[index].location, server_nodes[index].mb_nd);
+				// We try to shut down as much as possible, so we do not return noW!
+			}
+			server_nodes[index].mb_nd = -1;
+		}
+		res |= close;
+		server_nodes[index].init_state = 0;
+	}
+
+	/* destroy the mutex of each client request */
+	for (index=0; index < NUMBER_OF_CLIENT_REQTS; index ++) {
+		if (pthread_mutex_destroy(&(client_requests[index].coms_buf_mutex))) {
+			fprintf(stderr, "Modbus plugin: Error destroying request for modbus client node %%s\n", client_nodes[client_requests[index].client_node_id].location);
+			// We try to shut down as much as possible, so we do not return noW!
+			res |= -1;
+		}
+	}
+
+	/* modbus library close */
+	//fprintf(stderr, "Shutting down modbus library...\n");
+	if (mb_slave_and_master_done()<0) {
+		fprintf(stderr, "Modbus plugin: Error shutting down modbus library\n");
+		res |= -1;
+	}
+
+	return res;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modbus/mb_runtime.h	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,148 @@
+/* File generated by Beremiz (PlugGenerate_C method of modbus Plugin instance) */
+
+/*
+ * Copyright (c) 2016 Mario de Sousa (msousa@fe.up.pt)
+ *
+ * This file is part of the Modbus library for Beremiz and matiec.
+ *
+ * This Modbus library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this Modbus library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This code is made available on the understanding that it will not be
+ * used in safety-critical situations without a full and competent review.
+ */
+
+#include "mb_addr.h"
+#include "mb_tcp_private.h"
+#include "mb_master_private.h"
+
+
+
+#define DEF_REQ_SEND_RETRIES 0
+
+  // Used by the Modbus server node
+#define MEM_AREA_SIZE 65536
+typedef struct{
+	    u16		ro_bits [MEM_AREA_SIZE];
+	    u16		rw_bits [MEM_AREA_SIZE];
+	    u16		ro_words[MEM_AREA_SIZE];
+	    u16		rw_words[MEM_AREA_SIZE];
+	} server_mem_t;
+
+typedef struct{
+	    const char *location;
+	    u8		slave_id;
+	    node_addr_t	node_address;
+	    int		mb_nd;      // modbus library node used for this server 
+	    int		init_state; // store how far along the server's initialization has progressed
+	    pthread_t	thread_id;  // thread handling this server
+	    server_mem_t	mem_area;
+	} server_node_t;
+
+
+  // Used by the Modbus client node
+typedef struct{
+	    const char *location;
+	    node_addr_t	node_address;
+	    int		mb_nd;
+	    int		init_state; // store how far along the client's initialization has progressed
+	    u64		comm_period;
+	    int		prev_error; // error code of the last printed error message (0 when no error) 
+	    pthread_t	thread_id;  // thread handling all communication with this client
+	} client_node_t;
+
+
+  // Used by the Modbus client plugin
+typedef enum {
+	    req_input,
+	    req_output,
+	    no_request		/* just for tests to quickly disable a request */
+	} iotype_t;
+
+#define REQ_BUF_SIZE 2000
+typedef struct{
+	    const char *location;
+	    int		client_node_id;
+	    u8		slave_id;
+	    iotype_t	req_type;
+	    u8		mb_function;
+	    u16		address;
+	    u16		count;
+	    int		retries;
+	    u8		error_code; // modbus error code (if any) of current request
+	    int		prev_error; // error code of the last printed error message (0 when no error) 
+	    struct timespec resp_timeout;
+	      // buffer used to store located PLC variables
+	    u16		plcv_buffer[REQ_BUF_SIZE];
+	      // buffer used to store data coming from / going to server
+	    u16		coms_buffer[REQ_BUF_SIZE]; 
+	    pthread_mutex_t coms_buf_mutex; // mutex to access coms_buffer[]
+	} client_request_t;
+
+
+/* The total number of nodes, needed to support _all_ instances of the modbus plugin */
+#define TOTAL_TCPNODE_COUNT       %(total_tcpnode_count)s
+#define TOTAL_RTUNODE_COUNT       %(total_rtunode_count)s
+#define TOTAL_ASCNODE_COUNT       %(total_ascnode_count)s
+
+/* Values for instance %(locstr)s of the modbus plugin */
+#define MAX_NUMBER_OF_TCPCLIENTS  %(max_remote_tcpclient)s
+
+#define NUMBER_OF_TCPSERVER_NODES %(tcpserver_node_count)s
+#define NUMBER_OF_TCPCLIENT_NODES %(tcpclient_node_count)s
+#define NUMBER_OF_TCPCLIENT_REQTS %(tcpclient_reqs_count)s
+
+#define NUMBER_OF_RTUSERVER_NODES %(rtuserver_node_count)s
+#define NUMBER_OF_RTUCLIENT_NODES %(rtuclient_node_count)s
+#define NUMBER_OF_RTUCLIENT_REQTS %(rtuclient_reqs_count)s
+
+#define NUMBER_OF_ASCIISERVER_NODES %(ascserver_node_count)s
+#define NUMBER_OF_ASCIICLIENT_NODES %(ascclient_node_count)s
+#define NUMBER_OF_ASCIICLIENT_REQTS %(ascclient_reqs_count)s
+
+#define NUMBER_OF_SERVER_NODES (NUMBER_OF_TCPSERVER_NODES + \
+                                NUMBER_OF_RTUSERVER_NODES + \
+                                NUMBER_OF_ASCIISERVER_NODES)
+
+#define NUMBER_OF_CLIENT_NODES (NUMBER_OF_TCPCLIENT_NODES + \
+                                NUMBER_OF_RTUCLIENT_NODES + \
+                                NUMBER_OF_ASCIICLIENT_NODES)
+
+#define NUMBER_OF_CLIENT_REQTS (NUMBER_OF_TCPCLIENT_REQTS + \
+                                NUMBER_OF_RTUCLIENT_REQTS + \
+                                NUMBER_OF_ASCIICLIENT_REQTS)
+
+
+/*initialization following all parameters given by user in application*/
+
+static client_node_t		client_nodes[NUMBER_OF_CLIENT_NODES] = {
+%(client_nodes_params)s
+};
+
+
+static client_request_t	client_requests[NUMBER_OF_CLIENT_REQTS] = {
+%(client_req_params)s
+};
+
+
+static server_node_t		server_nodes[NUMBER_OF_SERVER_NODES] = {
+%(server_nodes_params)s
+}
+;
+
+/*******************/
+/*located variables*/
+/*******************/
+
+%(loc_vars)s
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modbus/mb_utils.py	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,223 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# This file is part of Beremiz, a Integrated Development Environment for
+# programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
+#
+# Copyright (c) 2016 Mario de Sousa (msousa@fe.up.pt)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# This code is made available on the understanding that it will not be
+# used in safety-critical situations without a full and competent review.
+
+
+# dictionary implementing:
+# key   - string with the description we want in the request plugin GUI
+# tuple - (modbus function number, request type, max count value,
+# data_type, bit_size)
+modbus_function_dict = {
+    "01 - Read Coils":                ('1',  'req_input', 2000, "BOOL",  1, "Q", "X", "Coil"),
+    "02 - Read Input Discretes":      ('2',  'req_input', 2000, "BOOL",  1, "I", "X", "Input Discrete"),
+    "03 - Read Holding Registers":    ('3',  'req_input',  125, "WORD", 16, "Q", "W", "Holding Register"),
+    "04 - Read Input Registers":      ('4',  'req_input',  125, "WORD", 16, "I", "W", "Input Register"),
+    "05 - Write Single coil":         ('5', 'req_output',    1, "BOOL",  1, "Q", "X", "Coil"),
+    "06 - Write Single Register":     ('6', 'req_output',    1, "WORD", 16, "Q", "W", "Holding Register"),
+    "15 - Write Multiple Coils":     ('15', 'req_output', 1968, "BOOL",  1, "Q", "X", "Coil"),
+    "16 - Write Multiple Registers": ('16', 'req_output',  123, "WORD", 16, "Q", "W", "Holding Register")}
+
+
+# Configuration tree value acces helper
+def GetCTVal(child, index):
+    return child.GetParamsAttributes()[0]["children"][index]["value"]
+
+
+# Configuration tree value acces helper, for multiple values
+def GetCTVals(child, indexes):
+    return map(lambda index: GetCTVal(child, index), indexes)
+
+
+def GetTCPServerNodePrinted(self, child):
+    """
+    Outputs a string to be used on C files
+    params: child - the correspondent subplugin in Beremiz
+    """
+    node_init_template = '''/*node %(locnodestr)s*/
+{"%(locnodestr)s", %(slaveid)s, {naf_tcp, {.tcp = {%(host)s, "%(port)s", DEF_CLOSE_ON_SILENCE}}}, -1 /* mb_nd */, 0 /* init_state */}'''
+
+    location = ".".join(map(str, child.GetCurrentLocation()))
+    host, port, slaveid = GetCTVals(child, range(3))
+    if host == "#ANY#":
+        host = 'INADDR_ANY'
+    else:
+        host = '"' + host + '"'
+    # slaveid = GetCTVal(child, 2)
+    # if int(slaveid) not in xrange(256):
+        # self.GetCTRoot().logger.write_error("Error: Wrong slave ID in %s server node\nModbus Plugin C code returns empty\n"%location)
+        # return None
+
+    node_dict = {"locnodestr": location,
+                 "host": host,
+                 "port": port,
+                 "slaveid": slaveid}
+    return node_init_template % node_dict
+
+
+def GetTCPServerMemAreaPrinted(self, child, nodeid):
+    """
+    Outputs a string to be used on C files
+    params: child - the correspondent subplugin in Beremiz
+            nodeid - on C code, each request has it's own parent node (sequential, 0..NUMBER_OF_NODES)
+                     It's this parameter.
+    return: None - if any definition error found
+            The string that should be added on C code - if everything goes allright
+    """
+    request_dict = {}
+
+    request_dict["locreqstr"] = "_".join(map(str, child.GetCurrentLocation()))
+    request_dict["nodeid"] = str(nodeid)
+    request_dict["address"] = GetCTVal(child, 2)
+    if int(request_dict["address"]) not in xrange(65536):
+        self.GetCTRoot().logger.write_error(
+            "Modbus plugin: Invalid Start Address in server memory area node %(locreqstr)s (Must be in the range [0..65535])\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
+        return None
+    request_dict["count"] = GetCTVal(child, 1)
+    if int(request_dict["count"]) not in xrange(1, 65536):
+        self.GetCTRoot().logger.write_error(
+            "Modbus plugin: Invalid number of channels in server memory area node %(locreqstr)s (Must be in the range [1..65536-start_address])\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
+        return None
+    if (int(request_dict["address"]) + int(request_dict["count"])) not in xrange(1, 65537):
+        self.GetCTRoot().logger.write_error(
+            "Modbus plugin: Invalid number of channels in server memory area node %(locreqstr)s (Must be in the range [1..65536-start_address])\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
+        return None
+
+    return ""
+
+
+modbus_serial_baudrate_list = [
+    "110", "300", "600", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200"]
+modbus_serial_stopbits_list = ["1", "2"]
+modbus_serial_parity_dict = {"none": 0, "odd": 1, "even": 2}
+
+
+def GetRTUSlaveNodePrinted(self, child):
+    """
+    Outputs a string to be used on C files
+    params: child - the correspondent subplugin in Beremiz
+    """
+    node_init_template = '''/*node %(locnodestr)s*/
+{"%(locnodestr)s", %(slaveid)s, {naf_rtu, {.rtu = {"%(device)s", %(baud)s /*baud*/, %(parity)s /*parity*/, 8 /*data bits*/, %(stopbits)s, 0 /* ignore echo */}}}, -1 /* mb_nd */, 0 /* init_state */}'''
+
+    location = ".".join(map(str, child.GetCurrentLocation()))
+    device, baud, parity, stopbits, slaveid = GetCTVals(child, range(5))
+
+    node_dict = {"locnodestr": location,
+                 "device": device,
+                 "baud": baud,
+                 "parity": modbus_serial_parity_dict[parity],
+                 "stopbits": stopbits,
+                 "slaveid": slaveid}
+    return node_init_template % node_dict
+
+
+def GetRTUClientNodePrinted(self, child):
+    """
+    Outputs a string to be used on C files
+    params: child - the correspondent subplugin in Beremiz
+    """
+    node_init_template = '''/*node %(locnodestr)s*/
+{"%(locnodestr)s", {naf_rtu, {.rtu = {"%(device)s", %(baud)s /*baud*/, %(parity)s /*parity*/, 8 /*data bits*/, %(stopbits)s, 0 /* ignore echo */}}}, -1 /* mb_nd */, 0 /* init_state */, %(coms_period)s /* communication period */}'''
+
+    location = ".".join(map(str, child.GetCurrentLocation()))
+    device, baud, parity, stopbits, coms_period = GetCTVals(child, range(5))
+
+    node_dict = {"locnodestr": location,
+                 "device": device,
+                 "baud": baud,
+                 "parity": modbus_serial_parity_dict[parity],
+                 "stopbits": stopbits,
+                 "coms_period": coms_period}
+    return node_init_template % node_dict
+
+
+def GetTCPClientNodePrinted(self, child):
+    """
+    Outputs a string to be used on C files
+    params: child - the correspondent subplugin in Beremiz
+    """
+    node_init_template = '''/*node %(locnodestr)s*/
+{"%(locnodestr)s", {naf_tcp, {.tcp = {"%(host)s", "%(port)s", DEF_CLOSE_ON_SILENCE}}}, -1 /* mb_nd */, 0 /* init_state */, %(coms_period)s /* communication period */, 0 /* prev_error */}'''
+
+    location = ".".join(map(str, child.GetCurrentLocation()))
+    host, port, coms_period = GetCTVals(child, range(3))
+
+    node_dict = {"locnodestr": location,
+                 "host": host,
+                 "port": port,
+                 "coms_period": coms_period}
+    return node_init_template % node_dict
+
+
+def GetClientRequestPrinted(self, child, nodeid):
+    """
+    Outputs a string to be used on C files
+    params: child - the correspondent subplugin in Beremiz
+            nodeid - on C code, each request has it's own parent node (sequential, 0..NUMBER_OF_NODES)
+                     It's this parameter.
+    return: None - if any definition error found
+            The string that should be added on C code - if everything goes allright
+    """
+
+    req_init_template = '''/*request %(locreqstr)s*/
+{"%(locreqstr)s", %(nodeid)s, %(slaveid)s, %(iotype)s, %(func_nr)s, %(address)s , %(count)s,
+DEF_REQ_SEND_RETRIES, 0 /* error_code */, 0 /* prev_code */, {%(timeout_s)d, %(timeout_ns)d} /* timeout */,
+{%(buffer)s}, {%(buffer)s}}'''
+
+    timeout = int(GetCTVal(child, 4))
+    timeout_s = int(timeout / 1000)
+    timeout_ms = timeout - (timeout_s * 1000)
+    timeout_ns = timeout_ms * 1000000
+
+    request_dict = {
+        "locreqstr": "_".join(map(str, child.GetCurrentLocation())),
+        "nodeid": str(nodeid),
+        "slaveid": GetCTVal(child, 1),
+        "address": GetCTVal(child, 3),
+        "count": GetCTVal(child, 2),
+        "timeout": timeout,
+        "timeout_s": timeout_s,
+        "timeout_ns": timeout_ns,
+        "buffer": ",".join(['0'] * int(GetCTVal(child, 2))),
+        "func_nr": modbus_function_dict[GetCTVal(child, 0)][0],
+        "iotype": modbus_function_dict[GetCTVal(child, 0)][1],
+        "maxcount": modbus_function_dict[GetCTVal(child, 0)][2]}
+
+    if int(request_dict["slaveid"]) not in xrange(256):
+        self.GetCTRoot().logger.write_error(
+            "Modbus plugin: Invalid slaveID in TCP client request node %(locreqstr)s (Must be in the range [0..255])\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
+        return None
+    if int(request_dict["address"]) not in xrange(65536):
+        self.GetCTRoot().logger.write_error(
+            "Modbus plugin: Invalid Start Address in TCP client request node %(locreqstr)s (Must be in the range [0..65535])\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
+        return None
+    if int(request_dict["count"]) not in xrange(1, 1 + int(request_dict["maxcount"])):
+        self.GetCTRoot().logger.write_error(
+            "Modbus plugin: Invalid number of channels in TCP client request node %(locreqstr)s (Must be in the range [1..%(maxcount)s])\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
+        return None
+    if (int(request_dict["address"]) + int(request_dict["count"])) not in xrange(1, 65537):
+        self.GetCTRoot().logger.write_error(
+            "Modbus plugin: Invalid number of channels in TCP client request node %(locreqstr)s (start_address + nr_channels must be less than 65536)\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
+        return None
+
+    return req_init_template % request_dict
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modbus/modbus.py	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,804 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# This file is part of Beremiz, a Integrated Development Environment for
+# programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
+#
+# Copyright (c) 2016 Mario de Sousa (msousa@fe.up.pt)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# This code is made available on the understanding that it will not be
+# used in safety-critical situations without a full and competent review.
+
+
+from __future__ import absolute_import
+import os
+from modbus.mb_utils import *
+
+from ConfigTreeNode import ConfigTreeNode
+from PLCControler import LOCATION_CONFNODE, LOCATION_VAR_MEMORY
+
+base_folder = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0]
+base_folder = os.path.join(base_folder, "..")
+ModbusPath = os.path.join(base_folder, "Modbus")
+
+
+#
+#
+#
+# C L I E N T    R E Q U E S T            #
+#
+#
+#
+
+
+class _RequestPlug(object):
+    XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+      <xsd:element name="ModbusRequest">
+        <xsd:complexType>
+          <xsd:attribute name="Function" type="xsd:string" use="optional" default="01 - Read Coils"/>
+          <xsd:attribute name="SlaveID" use="optional" default="1">
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:integer">
+                    <xsd:minInclusive value="0"/>
+                    <xsd:maxInclusive value="255"/>
+                </xsd:restriction>
+            </xsd:simpleType>
+          </xsd:attribute>
+          <xsd:attribute name="Nr_of_Channels" use="optional" default="1">
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:integer">
+                    <xsd:minInclusive value="1"/>
+                    <xsd:maxInclusive value="2000"/>
+                </xsd:restriction>
+            </xsd:simpleType>
+          </xsd:attribute>
+          <xsd:attribute name="Start_Address" use="optional" default="0">
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:integer">
+                    <xsd:minInclusive value="0"/>
+                    <xsd:maxInclusive value="65535"/>
+                </xsd:restriction>
+            </xsd:simpleType>
+          </xsd:attribute>
+          <xsd:attribute name="Timeout_in_ms" use="optional" default="10">
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:integer">
+                    <xsd:minInclusive value="1"/>
+                    <xsd:maxInclusive value="100000"/>
+                </xsd:restriction>
+            </xsd:simpleType>
+          </xsd:attribute>
+        </xsd:complexType>
+      </xsd:element>
+    </xsd:schema>
+    """
+
+    def GetParamsAttributes(self, path=None):
+        infos = ConfigTreeNode.GetParamsAttributes(self, path=path)
+        for element in infos:
+            if element["name"] == "ModbusRequest":
+                for child in element["children"]:
+                    if child["name"] == "Function":
+                        list = modbus_function_dict.keys()
+                        list.sort()
+                        child["type"] = list
+        return infos
+
+    def GetVariableLocationTree(self):
+        current_location = self.GetCurrentLocation()
+        name = self.BaseParams.getName()
+        address = self.GetParamsAttributes()[0]["children"][3]["value"]
+        count = self.GetParamsAttributes()[0]["children"][2]["value"]
+        function = self.GetParamsAttributes()[0]["children"][0]["value"]
+        # 'BOOL' or 'WORD'
+        datatype = modbus_function_dict[function][3]
+        # 1 or 16
+        datasize = modbus_function_dict[function][4]
+        # 'Q' for coils and holding registers, 'I' for input discretes and input registers
+        # datazone = modbus_function_dict[function][5]
+        # 'X' for bits, 'W' for words
+        datatacc = modbus_function_dict[function][6]
+        # 'Coil', 'Holding Register', 'Input Discrete' or 'Input Register'
+        dataname = modbus_function_dict[function][7]
+        entries = []
+        for offset in range(address, address + count):
+            entries.append({
+                "name": dataname + " " + str(offset),
+                "type": LOCATION_VAR_MEMORY,
+                "size": datasize,
+                "IEC_type": datatype,
+                "var_name": "var_name",
+                "location": datatacc + ".".join([str(i) for i in current_location]) + "." + str(offset),
+                "description": "description",
+                "children": []})
+        return {"name": name,
+                "type": LOCATION_CONFNODE,
+                "location": ".".join([str(i) for i in current_location]) + ".x",
+                "children": entries}
+
+    def CTNGenerate_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
+        """
+        return [], "", False
+
+
+#
+#
+#
+# S E R V E R    M E M O R Y    A R E A       #
+#
+#
+#
+
+# dictionary implementing:
+# key - string with the description we want in the request plugin GUI
+# list - (modbus function number, request type, max count value)
+modbus_memtype_dict = {
+    "01 - Coils":            ('1', 'rw_bits',  65536, "BOOL", 1, "Q", "X", "Coil"),
+    "02 - Input Discretes":  ('2', 'ro_bits',  65536, "BOOL", 1, "I", "X", "Input Discrete"),
+    "03 - Holding Registers": ('3', 'rw_words', 65536, "WORD", 16, "Q", "W", "Holding Register"),
+    "04 - Input Registers":  ('4', 'ro_words', 65536, "WORD", 16, "I", "W", "Input Register"),
+}
+
+
+class _MemoryAreaPlug(object):
+    XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+      <xsd:element name="MemoryArea">
+        <xsd:complexType>
+          <xsd:attribute name="MemoryAreaType" type="xsd:string" use="optional" default="01 - Coils"/>
+          <xsd:attribute name="Nr_of_Channels" use="optional" default="1">
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:integer">
+                    <xsd:minInclusive value="1"/>
+                    <xsd:maxInclusive value="65536"/>
+                </xsd:restriction>
+            </xsd:simpleType>
+          </xsd:attribute>
+          <xsd:attribute name="Start_Address" use="optional" default="0">
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:integer">
+                    <xsd:minInclusive value="0"/>
+                    <xsd:maxInclusive value="65535"/>
+                </xsd:restriction>
+            </xsd:simpleType>
+          </xsd:attribute>
+        </xsd:complexType>
+      </xsd:element>
+    </xsd:schema>
+    """
+
+    def GetParamsAttributes(self, path=None):
+        infos = ConfigTreeNode.GetParamsAttributes(self, path=path)
+        for element in infos:
+            if element["name"] == "MemoryArea":
+                for child in element["children"]:
+                    if child["name"] == "MemoryAreaType":
+                        list = modbus_memtype_dict.keys()
+                        list.sort()
+                        child["type"] = list
+        return infos
+
+    def GetVariableLocationTree(self):
+        current_location = self.GetCurrentLocation()
+        name = self.BaseParams.getName()
+        address = self.GetParamsAttributes()[0]["children"][2]["value"]
+        count = self.GetParamsAttributes()[0]["children"][1]["value"]
+        function = self.GetParamsAttributes()[0]["children"][0]["value"]
+        # 'BOOL' or 'WORD'
+        datatype = modbus_memtype_dict[function][3]
+        # 1 or 16
+        datasize = modbus_memtype_dict[function][4]
+        # 'Q' for coils and holding registers, 'I' for input discretes and input registers
+        # datazone = modbus_memtype_dict[function][5]
+        # 'X' for bits, 'W' for words
+        datatacc = modbus_memtype_dict[function][6]
+        # 'Coil', 'Holding Register', 'Input Discrete' or 'Input Register'
+        dataname = modbus_memtype_dict[function][7]
+        entries = []
+        for offset in range(address, address + count):
+            entries.append({
+                "name": dataname + " " + str(offset),
+                "type": LOCATION_VAR_MEMORY,
+                "size": datasize,
+                "IEC_type": datatype,
+                "var_name": "var_name",
+                "location": datatacc + ".".join([str(i) for i in current_location]) + "." + str(offset),
+                "description": "description",
+                "children": []})
+        return {"name": name,
+                "type": LOCATION_CONFNODE,
+                "location": ".".join([str(i) for i in current_location]) + ".x",
+                "children": entries}
+
+    def CTNGenerate_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
+        """
+        return [], "", False
+
+
+#
+#
+#
+# T C P    C L I E N T                 #
+#
+#
+#
+
+class _ModbusTCPclientPlug(object):
+    XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+      <xsd:element name="ModbusTCPclient">
+        <xsd:complexType>
+          <xsd:attribute name="Remote_IP_Address" type="xsd:string" use="optional" default="localhost"/>
+          <xsd:attribute name="Remote_Port_Number" type="xsd:string" use="optional" default="502"/>
+          <xsd:attribute name="Invocation_Rate_in_ms" use="optional" default="100">
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:unsignedLong">
+                    <xsd:minInclusive value="1"/>
+                    <xsd:maxInclusive value="2147483647"/>
+                </xsd:restriction>
+            </xsd:simpleType>
+          </xsd:attribute>
+        </xsd:complexType>
+      </xsd:element>
+    </xsd:schema>
+    """
+    # NOTE: Max value of 2147483647 (i32_max) for Invocation_Rate_in_ms
+    # corresponds to aprox 25 days.
+    CTNChildrenTypes = [("ModbusRequest", _RequestPlug, "Request")]
+    # TODO: Replace with CTNType !!!
+    PlugType = "ModbusTCPclient"
+
+    # Return the number of (modbus library) nodes this specific TCP client will need
+    #   return type: (tcp nodes, rtu nodes, ascii nodes)
+    def GetNodeCount(self):
+        return (1, 0, 0)
+
+    def CTNGenerate_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
+        """
+        return [], "", False
+
+
+#
+#
+#
+# T C P    S E R V E R                 #
+#
+#
+#
+
+class _ModbusTCPserverPlug(object):
+    # NOTE: the Port number is a 'string' and not an 'integer'!
+    # This is because the underlying modbus library accepts strings
+    # (e.g.: well known port names!)
+    XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+      <xsd:element name="ModbusServerNode">
+        <xsd:complexType>
+          <xsd:attribute name="Local_IP_Address" type="xsd:string" use="optional"  default="#ANY#"/>
+          <xsd:attribute name="Local_Port_Number" type="xsd:string" use="optional" default="502"/>
+          <xsd:attribute name="SlaveID" use="optional" default="0">
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:integer">
+                    <xsd:minInclusive value="0"/>
+                    <xsd:maxInclusive value="255"/>
+                </xsd:restriction>
+            </xsd:simpleType>
+          </xsd:attribute>
+        </xsd:complexType>
+      </xsd:element>
+    </xsd:schema>
+    """
+    CTNChildrenTypes = [("MemoryArea", _MemoryAreaPlug, "Memory Area")]
+    # TODO: Replace with CTNType !!!
+    PlugType = "ModbusTCPserver"
+
+    # Return the number of (modbus library) nodes this specific TCP server will need
+    #   return type: (tcp nodes, rtu nodes, ascii nodes)
+    def GetNodeCount(self):
+        return (1, 0, 0)
+
+    # Return a list with a single tuple conatining the (location, port number)
+    #     location: location of this node in the configuration tree
+    #     port number: IP port used by this Modbus/IP server
+    def GetIPServerPortNumbers(self):
+        port = self.GetParamsAttributes()[0]["children"][1]["value"]
+        return [(self.GetCurrentLocation(), port)]
+
+    def CTNGenerate_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
+        """
+        return [], "", False
+
+
+#
+#
+#
+# R T U    C L I E N T                 #
+#
+#
+#
+
+class _ModbusRTUclientPlug(object):
+    XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+      <xsd:element name="ModbusRTUclient">
+        <xsd:complexType>
+          <xsd:attribute name="Serial_Port" type="xsd:string"  use="optional" default="/dev/ttyS0"/>
+          <xsd:attribute name="Baud_Rate"   type="xsd:string"  use="optional" default="9600"/>
+          <xsd:attribute name="Parity"      type="xsd:string"  use="optional" default="even"/>
+          <xsd:attribute name="Stop_Bits"   type="xsd:string"  use="optional" default="1"/>
+          <xsd:attribute name="Invocation_Rate_in_ms" use="optional" default="100">
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:integer">
+                    <xsd:minInclusive value="1"/>
+                    <xsd:maxInclusive value="2147483647"/>
+                </xsd:restriction>
+            </xsd:simpleType>
+          </xsd:attribute>
+        </xsd:complexType>
+      </xsd:element>
+    </xsd:schema>
+    """
+    # NOTE: Max value of 2147483647 (i32_max) for Invocation_Rate_in_ms
+    # corresponds to aprox 25 days.
+    CTNChildrenTypes = [("ModbusRequest", _RequestPlug, "Request")]
+    # TODO: Replace with CTNType !!!
+    PlugType = "ModbusRTUclient"
+
+    def GetParamsAttributes(self, path=None):
+        infos = ConfigTreeNode.GetParamsAttributes(self, path=path)
+        for element in infos:
+            if element["name"] == "ModbusRTUclient":
+                for child in element["children"]:
+                    if child["name"] == "Baud_Rate":
+                        child["type"] = modbus_serial_baudrate_list
+                    if child["name"] == "Stop_Bits":
+                        child["type"] = modbus_serial_stopbits_list
+                    if child["name"] == "Parity":
+                        child["type"] = modbus_serial_parity_dict.keys()
+        return infos
+
+    # Return the number of (modbus library) nodes this specific RTU client will need
+    #   return type: (tcp nodes, rtu nodes, ascii nodes)
+    def GetNodeCount(self):
+        return (0, 1, 0)
+
+    def CTNGenerate_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
+        """
+        return [], "", False
+
+
+#
+#
+#
+# R T U    S L A V E                   #
+#
+#
+#
+
+
+class _ModbusRTUslavePlug(object):
+    XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+      <xsd:element name="ModbusRTUslave">
+        <xsd:complexType>
+          <xsd:attribute name="Serial_Port" type="xsd:string"  use="optional" default="/dev/ttyS0"/>
+          <xsd:attribute name="Baud_Rate"   type="xsd:string"  use="optional" default="9600"/>
+          <xsd:attribute name="Parity"      type="xsd:string"  use="optional" default="even"/>
+          <xsd:attribute name="Stop_Bits"   type="xsd:string"  use="optional" default="1"/>
+          <xsd:attribute name="SlaveID" use="optional" default="1">
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:integer">
+                    <xsd:minInclusive value="1"/>
+                    <xsd:maxInclusive value="255"/>
+                </xsd:restriction>
+            </xsd:simpleType>
+          </xsd:attribute>
+        </xsd:complexType>
+      </xsd:element>
+    </xsd:schema>
+    """
+    CTNChildrenTypes = [("MemoryArea", _MemoryAreaPlug, "Memory Area")]
+    # TODO: Replace with CTNType !!!
+    PlugType = "ModbusRTUslave"
+
+    def GetParamsAttributes(self, path=None):
+        infos = ConfigTreeNode.GetParamsAttributes(self, path=path)
+        for element in infos:
+            if element["name"] == "ModbusRTUslave":
+                for child in element["children"]:
+                    if child["name"] == "Baud_Rate":
+                        child["type"] = modbus_serial_baudrate_list
+                    if child["name"] == "Stop_Bits":
+                        child["type"] = modbus_serial_stopbits_list
+                    if child["name"] == "Parity":
+                        child["type"] = modbus_serial_parity_dict.keys()
+        return infos
+
+    # Return the number of (modbus library) nodes this specific RTU slave will need
+    #   return type: (tcp nodes, rtu nodes, ascii nodes)
+    def GetNodeCount(self):
+        return (0, 1, 0)
+
+    def CTNGenerate_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
+        """
+        return [], "", False
+
+
+def _lt_to_str(loctuple):
+    return '.'.join(map(str, loctuple))
+
+
+#
+#
+#
+# R O O T    C L A S S                #
+#
+#
+#
+class RootClass(object):
+    XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+      <xsd:element name="ModbusRoot">
+        <xsd:complexType>
+          <xsd:attribute name="MaxRemoteTCPclients" use="optional" default="10">
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:integer">
+                    <xsd:minInclusive value="0"/>
+                    <xsd:maxInclusive value="65535"/>
+                </xsd:restriction>
+            </xsd:simpleType>
+          </xsd:attribute>
+        </xsd:complexType>
+      </xsd:element>
+    </xsd:schema>
+    """
+    CTNChildrenTypes = [("ModbusTCPclient", _ModbusTCPclientPlug, "Modbus TCP Client"),
+                        ("ModbusTCPserver", _ModbusTCPserverPlug, "Modbus TCP Server"),
+                        ("ModbusRTUclient", _ModbusRTUclientPlug, "Modbus RTU Client"),
+                        ("ModbusRTUslave", _ModbusRTUslavePlug,  "Modbus RTU Slave")]
+
+    # Return the number of (modbus library) nodes this specific instance of the modbus plugin will need
+    #   return type: (tcp nodes, rtu nodes, ascii nodes)
+    def GetNodeCount(self):
+        max_remote_tcpclient = self.GetParamsAttributes()[
+            0]["children"][0]["value"]
+        total_node_count = (max_remote_tcpclient, 0, 0)
+        for child in self.IECSortedChildren():
+            # ask each child how many nodes it needs, and add them all up.
+            total_node_count = tuple(
+                x1 + x2 for x1, x2 in zip(total_node_count, child.GetNodeCount()))
+        return total_node_count
+
+    # Return a list with tuples of the (location, port numbers) used by all
+    # the Modbus/IP servers
+    def GetIPServerPortNumbers(self):
+        IPServer_port_numbers = []
+        for child in self.IECSortedChildren():
+            if child.CTNType == "ModbusTCPserver":
+                IPServer_port_numbers.extend(child.GetIPServerPortNumbers())
+        return IPServer_port_numbers
+
+    def CTNGenerate_C(self, buildpath, locations):
+        # print "#############"
+        # print self.__class__
+        # print type(self)
+        # print "self.CTNType >>>"
+        # print self.CTNType
+        # print "type(self.CTNType) >>>"
+        # print type(self.CTNType)
+        # print "#############"
+
+        loc_dict = {"locstr": "_".join(map(str, self.GetCurrentLocation()))}
+
+        # Determine the number of (modbus library) nodes ALL instances of the modbus plugin will need
+        #   total_node_count: (tcp nodes, rtu nodes, ascii nodes)
+        # Also get a list with tuples of (location, IP port numbers) used by all the Modbus/IP server nodes
+        #   This list is later used to search for duplicates in port numbers!
+        #   IPServer_port_numbers = [(location ,IPserver_port_number), ...]
+        #       location: tuple similar to (0, 3, 1) representing the location in the configuration tree "0.3.1.x"
+        # IPserver_port_number: a number (i.e. port number used by the
+        # Modbus/IP server)
+        total_node_count = (0, 0, 0)
+        IPServer_port_numbers = []
+        for CTNInstance in self.GetCTRoot().IterChildren():
+            if CTNInstance.CTNType == "modbus":
+                # ask each modbus plugin instance how many nodes it needs, and
+                # add them all up.
+                total_node_count = tuple(x1 + x2 for x1, x2 in zip(
+                    total_node_count, CTNInstance.GetNodeCount()))
+                IPServer_port_numbers.extend(
+                    CTNInstance.GetIPServerPortNumbers())
+
+        # Search for use of duplicate port numbers by Modbus/IP servers
+        # print IPServer_port_numbers
+        # ..but first define a lambda function to convert a tuple with the config tree location to a nice looking string
+        #   for e.g., convert the tuple (0, 3, 4) to "0.3.4"
+
+        for i in range(0, len(IPServer_port_numbers) - 1):
+            for j in range(i + 1, len(IPServer_port_numbers)):
+                if IPServer_port_numbers[i][1] == IPServer_port_numbers[j][1]:
+                    self.GetCTRoot().logger.write_warning(
+                        _("Error: Modbus/IP Servers %s.x and %s.x use the same port number %s.\n") % (
+                            _lt_to_str(IPServer_port_numbers[i][0]),
+                            _lt_to_str(IPServer_port_numbers[j][0]),
+                            IPServer_port_numbers[j][1]))
+                    raise Exception
+                    # TODO: return an error code instead of raising an
+                    # exception
+
+        # Determine the current location in Beremiz's project configuration
+        # tree
+        current_location = self.GetCurrentLocation()
+
+        # define a unique name for the generated C and h files
+        prefix = "_".join(map(str, current_location))
+        Gen_MB_c_path = os.path.join(buildpath, "MB_%s.c" % prefix)
+        Gen_MB_h_path = os.path.join(buildpath, "MB_%s.h" % prefix)
+        c_filename = os.path.join(os.path.split(__file__)[0], "mb_runtime.c")
+        h_filename = os.path.join(os.path.split(__file__)[0], "mb_runtime.h")
+
+        tcpclient_reqs_count = 0
+        rtuclient_reqs_count = 0
+        ascclient_reqs_count = 0
+        tcpclient_node_count = 0
+        rtuclient_node_count = 0
+        ascclient_node_count = 0
+        tcpserver_node_count = 0
+        rtuserver_node_count = 0
+        ascserver_node_count = 0
+        nodeid = 0
+        client_nodeid = 0
+        client_requestid = 0
+        server_id = 0
+
+        server_node_list = []
+        client_node_list = []
+        client_request_list = []
+        server_memarea_list = []
+        loc_vars = []
+        loc_vars_list = []  # list of variables already declared in C code!
+        for child in self.IECSortedChildren():
+            # print "<<<<<<<<<<<<<"
+            # print "child (self.IECSortedChildren())----->"
+            # print child.__class__
+            # print ">>>>>>>>>>>>>"
+            #
+            if child.PlugType == "ModbusTCPserver":
+                tcpserver_node_count += 1
+                new_node = GetTCPServerNodePrinted(self, child)
+                if new_node is None:
+                    return [], "", False
+                server_node_list.append(new_node)
+                #
+                for subchild in child.IECSortedChildren():
+                    new_memarea = GetTCPServerMemAreaPrinted(
+                        self, subchild, nodeid)
+                    if new_memarea is None:
+                        return [], "", False
+                    server_memarea_list.append(new_memarea)
+                    function = subchild.GetParamsAttributes()[
+                        0]["children"][0]["value"]
+                    # 'ro_bits', 'rw_bits', 'ro_words' or 'rw_words'
+                    memarea = modbus_memtype_dict[function][1]
+                    for iecvar in subchild.GetLocations():
+                        # print repr(iecvar)
+                        absloute_address = iecvar["LOC"][3]
+                        start_address = int(GetCTVal(subchild, 2))
+                        relative_addr = absloute_address - start_address
+                        # test if relative address in request specified range
+                        if relative_addr in xrange(int(GetCTVal(subchild, 1))):
+                            if str(iecvar["NAME"]) not in loc_vars_list:
+                                loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.%s[%d];" % (
+                                    server_id, memarea, absloute_address))
+                                loc_vars_list.append(str(iecvar["NAME"]))
+                server_id += 1
+            #
+            if child.PlugType == "ModbusRTUslave":
+                rtuserver_node_count += 1
+                new_node = GetRTUSlaveNodePrinted(self, child)
+                if new_node is None:
+                    return [], "", False
+                server_node_list.append(new_node)
+                #
+                for subchild in child.IECSortedChildren():
+                    new_memarea = GetTCPServerMemAreaPrinted(
+                        self, subchild, nodeid)
+                    if new_memarea is None:
+                        return [], "", False
+                    server_memarea_list.append(new_memarea)
+                    function = subchild.GetParamsAttributes()[
+                        0]["children"][0]["value"]
+                    # 'ro_bits', 'rw_bits', 'ro_words' or 'rw_words'
+                    memarea = modbus_memtype_dict[function][1]
+                    for iecvar in subchild.GetLocations():
+                        # print repr(iecvar)
+                        absloute_address = iecvar["LOC"][3]
+                        start_address = int(GetCTVal(subchild, 2))
+                        relative_addr = absloute_address - start_address
+                        # test if relative address in request specified range
+                        if relative_addr in xrange(int(GetCTVal(subchild, 1))):
+                            if str(iecvar["NAME"]) not in loc_vars_list:
+                                loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.%s[%d];" % (
+                                    server_id, memarea, absloute_address))
+                                loc_vars_list.append(str(iecvar["NAME"]))
+                server_id += 1
+            #
+            if child.PlugType == "ModbusTCPclient":
+                tcpclient_reqs_count += len(child.IECSortedChildren())
+                new_node = GetTCPClientNodePrinted(self, child)
+                if new_node is None:
+                    return [], "", False
+                client_node_list.append(new_node)
+                for subchild in child.IECSortedChildren():
+                    new_req = GetClientRequestPrinted(
+                        self, subchild, client_nodeid)
+                    if new_req is None:
+                        return [], "", False
+                    client_request_list.append(new_req)
+                    for iecvar in subchild.GetLocations():
+                        # absloute address - start address
+                        relative_addr = iecvar["LOC"][3] - int(GetCTVal(subchild, 3))
+                        # test if relative address in request specified range
+                        if relative_addr in xrange(int(GetCTVal(subchild, 2))):
+                            if str(iecvar["NAME"]) not in loc_vars_list:
+                                loc_vars.append(
+                                    "u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].plcv_buffer[%d];" % (client_requestid, relative_addr))
+                                loc_vars_list.append(str(iecvar["NAME"]))
+                    client_requestid += 1
+                tcpclient_node_count += 1
+                client_nodeid += 1
+            #
+            if child.PlugType == "ModbusRTUclient":
+                rtuclient_reqs_count += len(child.IECSortedChildren())
+                new_node = GetRTUClientNodePrinted(self, child)
+                if new_node is None:
+                    return [], "", False
+                client_node_list.append(new_node)
+                for subchild in child.IECSortedChildren():
+                    new_req = GetClientRequestPrinted(
+                        self, subchild, client_nodeid)
+                    if new_req is None:
+                        return [], "", False
+                    client_request_list.append(new_req)
+                    for iecvar in subchild.GetLocations():
+                        # absloute address - start address
+                        relative_addr = iecvar["LOC"][3] - int(GetCTVal(subchild, 3))
+                        # test if relative address in request specified range
+                        if relative_addr in xrange(int(GetCTVal(subchild, 2))):
+                            if str(iecvar["NAME"]) not in loc_vars_list:
+                                loc_vars.append(
+                                    "u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].plcv_buffer[%d];" % (client_requestid, relative_addr))
+                                loc_vars_list.append(str(iecvar["NAME"]))
+                    client_requestid += 1
+                rtuclient_node_count += 1
+                client_nodeid += 1
+            nodeid += 1
+
+        loc_dict["loc_vars"] = "\n".join(loc_vars)
+        loc_dict["server_nodes_params"] = ",\n\n".join(server_node_list)
+        loc_dict["client_nodes_params"] = ",\n\n".join(client_node_list)
+        loc_dict["client_req_params"] = ",\n\n".join(client_request_list)
+        loc_dict["tcpclient_reqs_count"] = str(tcpclient_reqs_count)
+        loc_dict["tcpclient_node_count"] = str(tcpclient_node_count)
+        loc_dict["tcpserver_node_count"] = str(tcpserver_node_count)
+        loc_dict["rtuclient_reqs_count"] = str(rtuclient_reqs_count)
+        loc_dict["rtuclient_node_count"] = str(rtuclient_node_count)
+        loc_dict["rtuserver_node_count"] = str(rtuserver_node_count)
+        loc_dict["ascclient_reqs_count"] = str(ascclient_reqs_count)
+        loc_dict["ascclient_node_count"] = str(ascclient_node_count)
+        loc_dict["ascserver_node_count"] = str(ascserver_node_count)
+        loc_dict["total_tcpnode_count"] = str(total_node_count[0])
+        loc_dict["total_rtunode_count"] = str(total_node_count[1])
+        loc_dict["total_ascnode_count"] = str(total_node_count[2])
+        loc_dict["max_remote_tcpclient"] = int(
+            self.GetParamsAttributes()[0]["children"][0]["value"])
+
+        # get template file content into a string, format it with dict
+        # and write it to proper .h file
+        mb_main = open(h_filename).read() % loc_dict
+        f = open(Gen_MB_h_path, 'w')
+        f.write(mb_main)
+        f.close()
+        # same thing as above, but now to .c file
+        mb_main = open(c_filename).read() % loc_dict
+        f = open(Gen_MB_c_path, 'w')
+        f.write(mb_main)
+        f.close()
+
+        LDFLAGS = []
+        LDFLAGS.append(" \"-L" + ModbusPath + "\"")
+        LDFLAGS.append(" -lmb ")
+        LDFLAGS.append(" \"-Wl,-rpath," + ModbusPath + "\"")
+        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_slave_and_master.o") + "\"")
+        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_slave.o") + "\"")
+        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_master.o") + "\"")
+        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_tcp.o")    + "\"")
+        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_rtu.o")    + "\"")
+        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_ascii.o")    + "\"")
+        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "sin_util.o")  + "\"")
+        # Target is ARM with linux and not win on x86 so winsock2 (ws2_32) library is useless !!!
+        # if os.name == 'nt':   # other possible values: 'posix' 'os2' 'ce' 'java' 'riscos'
+        # LDFLAGS.append(" -lws2_32 ")  # on windows we need to load winsock
+        # library!
+
+        return [(Gen_MB_c_path, ' -I"' + ModbusPath + '"')], LDFLAGS, True
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plcopen/BlockInstanceCollector.py	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,188 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# This file is part of Beremiz.
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+from collections import OrderedDict, namedtuple
+from plcopen.XSLTModelQuery import XSLTModelQuery, _StringValue, _BoolValue, _translate_args
+
+# -------------------------------------------------------------------------------
+#           Helpers object for generating pou block instances list
+# -------------------------------------------------------------------------------
+
+
+_Point = namedtuple("Point", ["x", "y"])
+
+_BlockInstanceInfos = namedtuple(
+    "BlockInstanceInfos",
+    ["type", "id", "x", "y", "width", "height", "specific_values", "inputs", "outputs"])
+
+_BlockSpecificValues = (
+    namedtuple("BlockSpecificValues",
+               ["name", "execution_order"]),
+    [_StringValue, int])
+_VariableSpecificValues = (
+    namedtuple("VariableSpecificValues",
+               ["name", "value_type", "execution_order"]),
+    [_StringValue, _StringValue, int])
+_ConnectionSpecificValues = (
+    namedtuple("ConnectionSpecificValues", ["name"]),
+    [_StringValue])
+
+_PowerRailSpecificValues = (
+    namedtuple("PowerRailSpecificValues", ["connectors"]),
+    [int])
+
+_LDElementSpecificValues = (
+    namedtuple("LDElementSpecificValues",
+               ["name", "negated", "edge", "storage", "execution_order"]),
+    [_StringValue, _BoolValue, _StringValue, _StringValue, int])
+
+_DivergenceSpecificValues = (
+    namedtuple("DivergenceSpecificValues", ["connectors"]),
+    [int])
+
+_SpecificValuesTuples = {
+    "comment": (
+        namedtuple("CommentSpecificValues", ["content"]),
+        [_StringValue]),
+    "input": _VariableSpecificValues,
+    "output": _VariableSpecificValues,
+    "inout": _VariableSpecificValues,
+    "connector": _ConnectionSpecificValues,
+    "continuation": _ConnectionSpecificValues,
+    "leftPowerRail": _PowerRailSpecificValues,
+    "rightPowerRail": _PowerRailSpecificValues,
+    "contact": _LDElementSpecificValues,
+    "coil": _LDElementSpecificValues,
+    "step": (
+        namedtuple("StepSpecificValues", ["name", "initial", "action"]),
+        [_StringValue, _BoolValue, lambda x: x]),
+    "transition": (
+        namedtuple("TransitionSpecificValues",
+                   ["priority", "condition_type", "condition", "connection"]),
+        [int, _StringValue, _StringValue, lambda x: x]),
+    "selectionDivergence": _DivergenceSpecificValues,
+    "selectionConvergence": _DivergenceSpecificValues,
+    "simultaneousDivergence": _DivergenceSpecificValues,
+    "simultaneousConvergence": _DivergenceSpecificValues,
+    "jump": (
+        namedtuple("JumpSpecificValues", ["target"]),
+        [_StringValue]),
+    "actionBlock": (
+        namedtuple("ActionBlockSpecificValues", ["actions"]),
+        [lambda x: x]),
+}
+
+_InstanceConnectionInfos = namedtuple(
+    "InstanceConnectionInfos",
+    ["name", "negated", "edge", "position", "links"])
+
+_ConnectionLinkInfos = namedtuple(
+    "ConnectionLinkInfos",
+    ["refLocalId", "formalParameter", "points"])
+
+
+class _ActionInfos(object):
+    __slots__ = ["qualifier", "type", "value", "duration", "indicator"]
+
+    def __init__(self, *args):
+        for attr, value in zip(self.__slots__, args):
+            setattr(self, attr, value if value is not None else "")
+
+    def copy(self):
+        return _ActionInfos(*[getattr(self, attr) for attr in self.__slots__])
+
+
+class BlockInstanceFactory(object):
+
+    def __init__(self, block_instances):
+        self.BlockInstances = block_instances
+        self.CurrentInstance = None
+        self.SpecificValues = None
+        self.CurrentConnection = None
+        self.CurrentLink = None
+
+    def SetSpecificValues(self, context, *args):
+        self.SpecificValues = list(args)
+        self.CurrentInstance = None
+        self.CurrentConnection = None
+        self.CurrentLink = None
+
+    def AddBlockInstance(self, context, *args):
+        specific_values_tuple, specific_values_translation = \
+            _SpecificValuesTuples.get(args[0][0], _BlockSpecificValues)
+
+        if args[0][0] == "step" and len(self.SpecificValues) < 3 or \
+           args[0][0] == "transition" and len(self.SpecificValues) < 4:
+            self.SpecificValues.append([None])
+        elif args[0][0] == "actionBlock" and len(self.SpecificValues) < 1:
+            self.SpecificValues.append([[]])
+        specific_values = specific_values_tuple(*_translate_args(
+            specific_values_translation, self.SpecificValues))
+        self.SpecificValues = None
+
+        self.CurrentInstance = _BlockInstanceInfos(
+            *(_translate_args([_StringValue, int] + [float] * 4, args) +
+              [specific_values, [], []]))
+
+        self.BlockInstances[self.CurrentInstance.id] = self.CurrentInstance
+
+    def AddInstanceConnection(self, context, *args):
+        connection_args = _translate_args(
+            [_StringValue] * 2 + [_BoolValue, _StringValue] + [float] * 2, args)
+
+        self.CurrentConnection = _InstanceConnectionInfos(
+            *(connection_args[1:4] + [
+                _Point(*connection_args[4:6]), []]))
+
+        if self.CurrentInstance is not None:
+            if connection_args[0] == "input":
+                self.CurrentInstance.inputs.append(self.CurrentConnection)
+            else:
+                self.CurrentInstance.outputs.append(self.CurrentConnection)
+        else:
+            self.SpecificValues.append([self.CurrentConnection])
+
+    def AddConnectionLink(self, context, *args):
+        self.CurrentLink = _ConnectionLinkInfos(
+            *(_translate_args([int, _StringValue], args) + [[]]))
+        self.CurrentConnection.links.append(self.CurrentLink)
+
+    def AddLinkPoint(self, context, *args):
+        self.CurrentLink.points.append(_Point(
+            *_translate_args([float] * 2, args)))
+
+    def AddAction(self, context, *args):
+        if len(self.SpecificValues) == 0:
+            self.SpecificValues.append([[]])
+        translated_args = _translate_args([_StringValue] * 5, args)
+        self.SpecificValues[0][0].append(_ActionInfos(*translated_args))
+
+
+class BlockInstanceCollector(XSLTModelQuery):
+    """ object for collecting instances path list"""
+    def __init__(self, controller):
+        XSLTModelQuery.__init__(self,
+                                controller,
+                                "pou_block_instances.xslt",
+                                [(name, self.FactoryCaller(name))
+                                 for name in ["AddBlockInstance",
+                                              "SetSpecificValues",
+                                              "AddInstanceConnection",
+                                              "AddConnectionLink",
+                                              "AddLinkPoint",
+                                              "AddAction"]])
+
+    def FactoryCaller(self, funcname):
+        def CallFactory(*args):
+            return getattr(self.factory, funcname)(*args)
+        return CallFactory
+
+    def Collect(self, root, debug):
+        element_instances = OrderedDict()
+        self.factory = BlockInstanceFactory(element_instances)
+        self._process_xslt(root, debug)
+        self.factory = None
+        return element_instances
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plcopen/InstanceTagnameCollector.py	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# This file is part of Beremiz.
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+from plcopen.XSLTModelQuery import XSLTModelQuery
+from plcopen.types_enums import *
+
+
+class InstanceTagName(object):
+    """Helpers object for generating instance tagname"""
+
+    def __init__(self):
+        self.TagName = None
+
+    def GetTagName(self):
+        return self.TagName
+
+    def ConfigTagName(self, context, *args):
+        self.TagName = ComputeConfigurationName(args[0][0])
+
+    def ResourceTagName(self, context, *args):
+        self.TagName = ComputeConfigurationResourceName(args[0][0], args[1][0])
+
+    def PouTagName(self, context, *args):
+        self.TagName = ComputePouName(args[0][0])
+
+    def ActionTagName(self, context, *args):
+        self.TagName = ComputePouActionName(args[0][0], args[0][1])
+
+    def TransitionTagName(self, context, *args):
+        self.TagName = ComputePouTransitionName(args[0][0], args[0][1])
+
+
+class InstanceTagnameCollector(XSLTModelQuery):
+    """ object for collecting instances path list"""
+    def __init__(self, controller):
+        XSLTModelQuery.__init__(self,
+                                controller,
+                                "instance_tagname.xslt",
+                                [(name, self.FactoryCaller(name))
+                                 for name in ["ConfigTagName",
+                                              "ResourceTagName",
+                                              "PouTagName",
+                                              "ActionTagName",
+                                              "TransitionTagName"]])
+
+    def FactoryCaller(self, funcname):
+        def CallFactory(*args):
+            return getattr(self.factory, funcname)(*args)
+        return CallFactory
+
+    def Collect(self, root, debug, instance_path):
+        self.factory = InstanceTagName()
+        self._process_xslt(root, debug, instance_path=instance_path)
+        res = self.factory.GetTagName()
+        self.factory = None
+        return res
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plcopen/InstancesPathCollector.py	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# This file is part of Beremiz.
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+from plcopen.XSLTModelQuery import XSLTModelQuery
+
+
+class InstancesPathCollector(XSLTModelQuery):
+    """ object for collecting instances path list"""
+    def __init__(self, controller):
+        self.Instances = []
+        XSLTModelQuery.__init__(self,
+                                controller,
+                                "instances_path.xslt",
+                                [("AddInstance", self.AddInstance)])
+
+    def AddInstance(self, context, *args):
+        self.Instances.append(args[0][0])
+
+    def Collect(self, root, name, debug):
+        self._process_xslt(root, debug, instance_type=name)
+        res = self.Instances
+        self.Instances = []
+        return res
--- a/plcopen/Makefile	Mon Feb 19 19:36:43 2018 +0300
+++ b/plcopen/Makefile	Fri Mar 02 17:01:25 2018 +0100
@@ -6,10 +6,10 @@
 
 all:$(xsltfiles)
 
-%.xslt: %.ysl2
+%.xslt: %.ysl2 yslt_noindent.yml2
 	$(yml)/yml2c -I $(yml) $< -o $@.tmp
 	xmlstarlet fo $@.tmp > $@
 	rm $@.tmp
 	
 clean:
-	rm -f $(xsltfiles)
\ No newline at end of file
+	rm -f $(xsltfiles)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plcopen/POUVariablesCollector.py	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# This file is part of Beremiz.
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+from plcopen.XSLTModelQuery import XSLTModelQuery, _StringValue, _BoolValue, _translate_args
+from plcopen.types_enums import CLASS_TYPES, POU_TYPES, VAR_CLASS_INFOS
+
+
+def class_extraction(value):
+    class_type = CLASS_TYPES.get(value)
+    if class_type is not None:
+        return class_type
+
+    pou_type = POU_TYPES.get(value)
+    if pou_type is not None:
+        return pou_type
+
+    var_type = VAR_CLASS_INFOS.get(value)
+    if var_type is not None:
+        return var_type[1]
+
+    return None
+
+
+class _VariablesTreeItemInfos(object):
+    __slots__ = ["name", "var_class", "type", "edit", "debug", "variables"]
+
+    def __init__(self, *args):
+        for attr, value in zip(self.__slots__, args):
+            setattr(self, attr, value if value is not None else "")
+
+    def copy(self):
+        return _VariablesTreeItemInfos(*[getattr(self, attr) for attr in self.__slots__])
+
+
+class VariablesTreeInfosFactory(object):
+
+    def __init__(self):
+        self.Root = None
+
+    def GetRoot(self):
+        return self.Root
+
+    def SetRoot(self, context, *args):
+        self.Root = _VariablesTreeItemInfos(
+            *([''] + _translate_args(
+                [class_extraction, _StringValue] + [_BoolValue] * 2,
+                args) + [[]]))
+
+    def AddVariable(self, context, *args):
+        if self.Root is not None:
+            self.Root.variables.append(_VariablesTreeItemInfos(
+                *(_translate_args(
+                    [_StringValue, class_extraction, _StringValue] +
+                    [_BoolValue] * 2, args) + [[]])))
+
+
+class POUVariablesCollector(XSLTModelQuery):
+    def __init__(self, controller):
+        XSLTModelQuery.__init__(self,
+                                controller,
+                                "pou_variables.xslt",
+                                [(name, self.FactoryCaller(name))
+                                 for name in ["SetRoot", "AddVariable"]])
+
+    def FactoryCaller(self, funcname):
+        def CallFactory(*args):
+            return getattr(self.factory, funcname)(*args)
+        return CallFactory
+
+    def Collect(self, root, debug):
+        self.factory = VariablesTreeInfosFactory()
+        self._process_xslt(root, debug)
+        res = self.factory.GetRoot()
+        self.factory = None
+        return res
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plcopen/VariableInfoCollector.py	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# This file is part of Beremiz.
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+from plcopen.XSLTModelQuery import XSLTModelQuery, _StringValue, _BoolValue, _translate_args
+
+# -------------------------------------------------------------------------------
+#                 Helpers object for generating pou var list
+# -------------------------------------------------------------------------------
+
+
+class _VariableInfos(object):
+    __slots__ = ["Name", "Class", "Option", "Location", "InitialValue",
+                 "Edit", "Documentation", "Type", "Tree", "Number"]
+
+    def __init__(self, *args):
+        for attr, value in zip(self.__slots__, args):
+            setattr(self, attr, value if value is not None else "")
+
+    def copy(self):
+        return _VariableInfos(*[getattr(self, attr) for attr in self.__slots__])
+
+
+class VariablesInfosFactory(object):
+    """ Helpers object for generating pou var list """
+
+    def __init__(self, variables):
+        self.Variables = variables
+        self.TreeStack = []
+        self.Type = None
+        self.Dimensions = None
+
+    def SetType(self, context, *args):
+        self.Type = args[0][0]
+
+    def GetType(self):
+        if len(self.Dimensions) > 0:
+            return ("array", self.Type, self.Dimensions)
+        return self.Type
+
+    def GetTree(self):
+        return (self.TreeStack.pop(-1), self.Dimensions)
+
+    def AddDimension(self, context, *args):
+        self.Dimensions.append(tuple(
+            _translate_args([_StringValue] * 2, args)))
+
+    def AddTree(self, context, *args):
+        self.TreeStack.append([])
+        self.Dimensions = []
+
+    def AddVarToTree(self, context, *args):
+        var = (args[0][0], self.Type, self.GetTree())
+        self.TreeStack[-1].append(var)
+
+    def AddVariable(self, context, *args):
+        self.Variables.append(_VariableInfos(*(
+            _translate_args([_StringValue] * 5 + [_BoolValue] + [_StringValue], args) +
+            [self.GetType(), self.GetTree()])))
+
+
+class VariableInfoCollector(XSLTModelQuery):
+    def __init__(self, controller):
+        XSLTModelQuery.__init__(self,
+                                controller,
+                                "variables_infos.xslt",
+                                [(name, self.FactoryCaller(name))
+                                 for name in [
+                                     "SetType",
+                                     "AddDimension",
+                                     "AddTree",
+                                     "AddVarToTree",
+                                     "AddVariable"]])
+
+    def FactoryCaller(self, funcname):
+        def CallFactory(*args):
+            return getattr(self.factory, funcname)(*args)
+        return CallFactory
+
+    def Collect(self, root, debug, variables, tree):
+        self.factory = VariablesInfosFactory(variables)
+        self._process_xslt(root, debug, tree=str(tree))
+        res = self.factory
+        self.factory = None
+        return res
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plcopen/XSLTModelQuery.py	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# This file is part of Beremiz.
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+import os
+from lxml import etree
+import util.paths as paths
+from plcopen.structures import StdBlckLibs
+
+ScriptDirectory = paths.AbsDir(__file__)
+
+
+class XSLTModelQuery(object):
+    """ a class to handle XSLT queries on project and libs """
+    def __init__(self, controller, xsltpath, ext=None):
+        # arbitrary set debug to false, updated later
+        self.debug = False
+
+        # merge xslt extensions for library access to query specific ones
+        xsltext = [
+            ("GetProject", lambda *_ignored:
+             [controller.GetProject(self.debug)]),
+            ("GetStdLibs", lambda *_ignored:
+             [lib for lib in StdBlckLibs.values()]),
+            ("GetExtensions", lambda *_ignored:
+             [ctn["types"] for ctn in controller.ConfNodeTypes])
+        ]
+
+        if ext is not None:
+            xsltext.extend(ext)
+
+        # parse and compile. "beremiz" arbitrary namespace for extensions
+        self.xslt = etree.XSLT(
+            etree.parse(
+                os.path.join(ScriptDirectory, xsltpath),
+                etree.XMLParser()),
+            extensions={("beremiz", name): call for name, call in xsltext})
+
+    def _process_xslt(self, root, debug, **kwargs):
+        self.debug = debug
+        res = self.xslt(root, **{k: etree.XSLT.strparam(v) for k, v in kwargs.iteritems()})
+        # print(self.xslt.error_log)
+        return res
+
+
+# -------------------------------------------------------------------------------
+#           Helpers functions for translating list of arguments
+#                       from xslt to valid arguments
+# -------------------------------------------------------------------------------
+
+
+def _StringValue(x):
+    return x
+
+
+def _BoolValue(x):
+    return x in ["true", "0"]
+
+
+def _translate_args(translations, args):
+    return [translate(arg[0]) if len(arg) > 0 else None
+            for translate, arg in
+            zip(translations, args)]
--- a/plcopen/instance_tagname.xslt	Mon Feb 19 19:36:43 2018 +0300
+++ b/plcopen/instance_tagname.xslt	Fri Mar 02 17:01:25 2018 +0100
@@ -1,20 +1,12 @@
 <?xml version="1.0"?>
-<xsl:stylesheet xmlns:func="http://exslt.org/functions" xmlns:dyn="http://exslt.org/dynamic" xmlns:str="http://exslt.org/strings" xmlns:math="http://exslt.org/math" xmlns:exsl="http://exslt.org/common" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:yml="http://fdik.org/yml" xmlns:set="http://exslt.org/sets" xmlns:ppx="http://www.plcopen.org/xml/tc6_0201" xmlns:ns="instance_tagname_ns" xmlns:regexp="http://exslt.org/regular-expressions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
+<xsl:stylesheet xmlns:exsl="http://exslt.org/common" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:ppx="http://www.plcopen.org/xml/tc6_0201" xmlns:ns="beremiz" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
   <xsl:output method="xml"/>
-  <xsl:variable name="space" select="'                                                                                                                                                                                                        '"/>
-  <xsl:param name="autoindent" select="4"/>
   <xsl:param name="instance_path"/>
-  <xsl:variable name="project">
-    <xsl:copy-of select="document('project')/project/*"/>
-  </xsl:variable>
-  <xsl:variable name="stdlib">
-    <xsl:copy-of select="document('stdlib')/stdlib/*"/>
-  </xsl:variable>
-  <xsl:variable name="extensions">
-    <xsl:copy-of select="document('extensions')/extensions/*"/>
-  </xsl:variable>
+  <xsl:variable name="project" select="ns:GetProject()"/>
+  <xsl:variable name="stdlib" select="ns:GetStdLibs()"/>
+  <xsl:variable name="extensions" select="ns:GetExtensions()"/>
+  <xsl:variable name="all_types" select="($project | $stdlib | $extensions)/ppx:types"/>
   <xsl:template name="element_name">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="path"/>
     <xsl:choose>
       <xsl:when test="contains($path,'.')">
@@ -26,7 +18,6 @@
     </xsl:choose>
   </xsl:template>
   <xsl:template name="next_path">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="path"/>
     <xsl:choose>
       <xsl:when test="contains($path,'.')">
@@ -35,14 +26,12 @@
     </xsl:choose>
   </xsl:template>
   <xsl:template match="ppx:project">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="config_name">
       <xsl:call-template name="element_name">
         <xsl:with-param name="path" select="$instance_path"/>
       </xsl:call-template>
     </xsl:variable>
     <xsl:apply-templates select="ppx:instances/ppx:configurations/ppx:configuration[@name=$config_name]">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="element_path">
         <xsl:call-template name="next_path">
           <xsl:with-param name="path" select="$instance_path"/>
@@ -51,7 +40,6 @@
     </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="ppx:configuration">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="element_path"/>
     <xsl:choose>
       <xsl:when test="$element_path!=''">
@@ -61,7 +49,6 @@
           </xsl:call-template>
         </xsl:variable>
         <xsl:apply-templates select="ppx:resource[@name=$child_name] | ppx:globalVars/ppx:variable[@name=$child_name]/ppx:type/*[self::ppx:derived or self::ppx:struct or self::ppx:array]">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
           <xsl:with-param name="element_path">
             <xsl:call-template name="next_path">
               <xsl:with-param name="path" select="$element_path"/>
@@ -75,7 +62,6 @@
     </xsl:choose>
   </xsl:template>
   <xsl:template match="ppx:resource">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="element_path"/>
     <xsl:choose>
       <xsl:when test="$element_path!=''">
@@ -87,7 +73,6 @@
           </xsl:call-template>
         </xsl:variable>
         <xsl:apply-templates select="ppx:pouInstance[@name=$child_name] | ppx:task/ppx:pouInstance[@name=$child_name] | ppx:globalVars/ppx:variable[@name=$child_name]/ppx:type/*[self::ppx:derived or self::ppx:struct or self::ppx:array]">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
           <xsl:with-param name="element_path">
             <xsl:call-template name="next_path">
               <xsl:with-param name="path" select="$element_path"/>
@@ -101,18 +86,15 @@
     </xsl:choose>
   </xsl:template>
   <xsl:template match="ppx:pouInstance">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="element_path"/>
     <xsl:variable name="type_name">
       <xsl:value-of select="@typeName"/>
     </xsl:variable>
-    <xsl:apply-templates select="exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                 exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                 exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                 exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                 exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                 exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
+    <xsl:apply-templates select="$all_types/ppx:pous/ppx:pou[@name=$type_name] |                  $all_types/ppx:dataTypes/ppx:dataType[@name=$type_name]">
       <xsl:with-param name="element_path" select="$element_path"/>
     </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="ppx:pou">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="element_path"/>
     <xsl:choose>
       <xsl:when test="$element_path!=''">
@@ -122,16 +104,13 @@
           </xsl:call-template>
         </xsl:variable>
         <xsl:apply-templates select="ppx:interface/*/ppx:variable[@name=$child_name]/ppx:type/*[self::ppx:derived or self::ppx:struct or self::ppx:array]">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
           <xsl:with-param name="element_path">
             <xsl:call-template name="next_path">
               <xsl:with-param name="path" select="$element_path"/>
             </xsl:call-template>
           </xsl:with-param>
         </xsl:apply-templates>
-        <xsl:apply-templates select="ppx:actions/ppx:action[@name=$child_name] | ppx:transitions/ppx:transition[@name=$child_name]">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-        </xsl:apply-templates>
+        <xsl:apply-templates select="ppx:actions/ppx:action[@name=$child_name] | ppx:transitions/ppx:transition[@name=$child_name]"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:variable name="name">
@@ -142,42 +121,33 @@
     </xsl:choose>
   </xsl:template>
   <xsl:template match="ppx:action">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="ns:ActionTagName(ancestor::ppx:pou/@name, @name)"/>
   </xsl:template>
   <xsl:template match="ppx:transition">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="ns:TransitionTagName(ancestor::ppx:pou/@name, @name)"/>
   </xsl:template>
   <xsl:template match="ppx:dataType">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="element_path"/>
     <xsl:apply-templates select="ppx:baseType/*[self::ppx:derived or self::ppx:struct or self::ppx:array]">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="element_path" select="$element_path"/>
     </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="ppx:derived">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="element_path"/>
     <xsl:variable name="type_name">
       <xsl:value-of select="@name"/>
     </xsl:variable>
-    <xsl:apply-templates select="exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                 exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                 exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                 exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                 exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                 exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
+    <xsl:apply-templates select="$all_types/ppx:pous/ppx:pou[@name=$type_name] |                  $all_types/ppx:dataTypes/ppx:dataType[@name=$type_name]">
       <xsl:with-param name="element_path" select="$element_path"/>
     </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="ppx:array">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="element_path"/>
     <xsl:apply-templates select="ppx:baseType/*[self::ppx:derived or self::ppx:struct or self::ppx:array]">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="element_path" select="$element_path"/>
     </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="ppx:struct">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="element_path"/>
     <xsl:variable name="child_name">
       <xsl:call-template name="element_name">
@@ -185,7 +155,6 @@
       </xsl:call-template>
     </xsl:variable>
     <xsl:apply-templates select="ppx:variable[@name=$child_name]/ppx:type/*[self::ppx:derived or self::ppx:struct or self::ppx:array]">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="element_path">
         <xsl:call-template name="next_path">
           <xsl:with-param name="path" select="$element_path"/>
--- a/plcopen/instance_tagname.ysl2	Mon Feb 19 19:36:43 2018 +0300
+++ b/plcopen/instance_tagname.ysl2	Fri Mar 02 17:01:25 2018 +0100
@@ -1,22 +1,19 @@
-include yslt.yml2
-estylesheet xmlns:ppx="http://www.plcopen.org/xml/tc6_0201"
+include yslt_noindent.yml2
+istylesheet xmlns:ppx="http://www.plcopen.org/xml/tc6_0201"
             xmlns:xhtml="http://www.w3.org/1999/xhtml"
-            xmlns:ns="instance_tagname_ns" 
+            xmlns:ns="beremiz" 
             extension-element-prefixes="ns" 
             exclude-result-prefixes="ns" {
     
     param "instance_path";
     
-    variable "project" {
-        copy "document('project')/project/*";
-    }
+    variable "project", "ns:GetProject()";
     
-    variable "stdlib" {
-        copy "document('stdlib')/stdlib/*";
-    }
-    variable "extensions" {
-        copy "document('extensions')/extensions/*";
-    }
+    variable "stdlib", "ns:GetStdLibs()";
+
+    variable "extensions", "ns:GetExtensions()";
+
+    variable "all_types", "($project | $stdlib | $extensions)/ppx:types";
     
     function "element_name" {
         param "path";
@@ -97,12 +94,8 @@
     template "ppx:pouInstance" {
         param "element_path";
         variable "type_name" > «@typeName»
-        apply """exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                 exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                 exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                 exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                 exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                 exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]""" {
+        apply """$all_types/ppx:pous/ppx:pou[@name=$type_name] | \
+                 $all_types/ppx:dataTypes/ppx:dataType[@name=$type_name]""" {
             with "element_path", "$element_path";
         }
     }
@@ -150,12 +143,8 @@
     template "ppx:derived" {
         param "element_path";
         variable "type_name" > «@name»
-        apply """exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                 exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                 exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                 exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                 exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                 exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]""" {
+        apply """$all_types/ppx:pous/ppx:pou[@name=$type_name] | \
+                 $all_types/ppx:dataTypes/ppx:dataType[@name=$type_name]""" {
             with "element_path", "$element_path";
         }
     }
--- a/plcopen/instances_path.xslt	Mon Feb 19 19:36:43 2018 +0300
+++ b/plcopen/instances_path.xslt	Fri Mar 02 17:01:25 2018 +0100
@@ -1,40 +1,23 @@
 <?xml version="1.0"?>
-<xsl:stylesheet xmlns:func="http://exslt.org/functions" xmlns:dyn="http://exslt.org/dynamic" xmlns:str="http://exslt.org/strings" xmlns:math="http://exslt.org/math" xmlns:exsl="http://exslt.org/common" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:yml="http://fdik.org/yml" xmlns:set="http://exslt.org/sets" xmlns:ppx="http://www.plcopen.org/xml/tc6_0201" xmlns:ns="instances_ns" xmlns:regexp="http://exslt.org/regular-expressions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
+<xsl:stylesheet xmlns:exsl="http://exslt.org/common" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:ppx="http://www.plcopen.org/xml/tc6_0201" xmlns:ns="beremiz" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
   <xsl:output method="xml"/>
-  <xsl:variable name="space" select="'                                                                                                                                                                                                        '"/>
-  <xsl:param name="autoindent" select="4"/>
   <xsl:param name="instance_type"/>
-  <xsl:template match="text()">
-    <xsl:param name="_indent" select="0"/>
-  </xsl:template>
-  <xsl:variable name="project">
-    <xsl:copy-of select="document('project')/project/*"/>
-  </xsl:variable>
-  <xsl:variable name="stdlib">
-    <xsl:copy-of select="document('stdlib')/stdlib/*"/>
-  </xsl:variable>
-  <xsl:variable name="extensions">
-    <xsl:copy-of select="document('extensions')/extensions/*"/>
-  </xsl:variable>
+  <xsl:template match="text()"/>
+  <xsl:variable name="project" select="ns:GetProject()"/>
+  <xsl:variable name="stdlib" select="ns:GetStdLibs()"/>
+  <xsl:variable name="extensions" select="ns:GetExtensions()"/>
+  <xsl:variable name="all_types" select="($project | $stdlib | $extensions)/ppx:types"/>
   <xsl:template match="ppx:project">
-    <xsl:param name="_indent" select="0"/>
-    <instances>
-      <xsl:apply-templates select="ppx:instances/ppx:configurations/ppx:configuration">
-        <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-      </xsl:apply-templates>
-    </instances>
+    <xsl:apply-templates select="ppx:instances/ppx:configurations/ppx:configuration"/>
   </xsl:template>
   <xsl:template match="ppx:configuration">
-    <xsl:param name="_indent" select="0"/>
     <xsl:apply-templates select="ppx:globalVars/ppx:variable[ppx:type/ppx:derived] | ppx:resource">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="parent_path">
         <xsl:value-of select="@name"/>
       </xsl:with-param>
     </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="ppx:resource">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="parent_path"/>
     <xsl:variable name="resource_path">
       <xsl:value-of select="$parent_path"/>
@@ -42,14 +25,12 @@
       <xsl:value-of select="@name"/>
     </xsl:variable>
     <xsl:apply-templates select="ppx:globalVars/ppx:variable[ppx:type/ppx:derived] | ppx:pouInstance | ppx:task/ppx:pouInstance">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="parent_path">
         <xsl:value-of select="$resource_path"/>
       </xsl:with-param>
     </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="ppx:pouInstance">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="parent_path"/>
     <xsl:variable name="pou_instance_path">
       <xsl:value-of select="$parent_path"/>
@@ -64,8 +45,7 @@
         <xsl:variable name="type_name">
           <xsl:value-of select="@typeName"/>
         </xsl:variable>
-        <xsl:apply-templates select="exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                         exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                         exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                         exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                         exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                         exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
+        <xsl:apply-templates select="$all_types/ppx:pous/ppx:pou[@name=$type_name] |                          $all_types/ppx:dataTypes/ppx:dataType[@name=$type_name]">
           <xsl:with-param name="instance_path">
             <xsl:value-of select="$pou_instance_path"/>
           </xsl:with-param>
@@ -74,27 +54,22 @@
     </xsl:choose>
   </xsl:template>
   <xsl:template match="ppx:pou">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="instance_path"/>
     <xsl:apply-templates select="ppx:interface/*/ppx:variable[ppx:type/ppx:derived]">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="parent_path">
         <xsl:value-of select="$instance_path"/>
       </xsl:with-param>
     </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="ppx:dataType">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="instance_path"/>
     <xsl:apply-templates select="ppx:baseType/*[self::ppx:derived or self::ppx:struct or self::ppx:array]">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="parent_path">
         <xsl:value-of select="$instance_path"/>
       </xsl:with-param>
     </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="ppx:variable">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="parent_path"/>
     <xsl:variable name="variable_path">
       <xsl:value-of select="$parent_path"/>
@@ -102,14 +77,12 @@
       <xsl:value-of select="@name"/>
     </xsl:variable>
     <xsl:apply-templates select="ppx:type/ppx:derived">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="variable_path">
         <xsl:value-of select="$variable_path"/>
       </xsl:with-param>
     </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="ppx:derived">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="variable_path"/>
     <xsl:choose>
       <xsl:when test="@name=$instance_type">
@@ -119,8 +92,7 @@
         <xsl:variable name="type_name">
           <xsl:value-of select="@name"/>
         </xsl:variable>
-        <xsl:apply-templates select="exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                         exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                         exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                         exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                         exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                         exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
+        <xsl:apply-templates select="$all_types/ppx:pous/ppx:pou[@name=$type_name] |                          $all_types/ppx:dataTypes/ppx:dataType[@name=$type_name]">
           <xsl:with-param name="instance_path">
             <xsl:value-of select="$variable_path"/>
           </xsl:with-param>
@@ -129,7 +101,6 @@
     </xsl:choose>
   </xsl:template>
   <xsl:template match="ppx:struct">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="variable_path"/>
     <xsl:for-each select="ppx:variable[ppx:type/ppx:derived or ppx:type/ppx:struct or ppx:type/ppx:array]">
       <xsl:variable name="element_path">
@@ -139,17 +110,14 @@
       </xsl:variable>
     </xsl:for-each>
     <xsl:apply-templates select="ppx:type/*[self::ppx:derived or self::ppx:struct or self::ppx:array]">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="variable_path">
         <xsl:value-of select="$element_path"/>
       </xsl:with-param>
     </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="ppx:array">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="variable_path"/>
     <xsl:apply-templates select="ppx:baseType/*[self::ppx:derived or self::ppx:struct or self::ppx:array]">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="variable_path">
         <xsl:value-of select="$variable_path"/>
       </xsl:with-param>
--- a/plcopen/instances_path.ysl2	Mon Feb 19 19:36:43 2018 +0300
+++ b/plcopen/instances_path.ysl2	Fri Mar 02 17:01:25 2018 +0100
@@ -1,7 +1,7 @@
-include yslt.yml2
-estylesheet xmlns:ppx="http://www.plcopen.org/xml/tc6_0201"
+include yslt_noindent.yml2
+istylesheet xmlns:ppx="http://www.plcopen.org/xml/tc6_0201"
             xmlns:xhtml="http://www.w3.org/1999/xhtml"
-            xmlns:ns="instances_ns" 
+            xmlns:ns="beremiz" 
             extension-element-prefixes="ns" 
             exclude-result-prefixes="ns" {
     
@@ -9,21 +9,16 @@
     
     template "text()";
     
-    variable "project" {
-        copy "document('project')/project/*";
-    }
+    variable "project", "ns:GetProject()";
     
-    variable "stdlib" {
-        copy "document('stdlib')/stdlib/*";
-    }
-    variable "extensions" {
-        copy "document('extensions')/extensions/*";
-    }
-    
+    variable "stdlib", "ns:GetStdLibs()";
+
+    variable "extensions", "ns:GetExtensions()";
+
+    variable "all_types", "($project | $stdlib | $extensions)/ppx:types";
+
     template "ppx:project" {
-        instances {
-            apply "ppx:instances/ppx:configurations/ppx:configuration";
-        }
+        apply "ppx:instances/ppx:configurations/ppx:configuration";
     }
     
     template "ppx:configuration" {
@@ -49,12 +44,8 @@
             }
             otherwise {
                 variable "type_name" > «@typeName»
-                apply """exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                         exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                         exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                         exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                         exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                         exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]""" {
+                apply """$all_types/ppx:pous/ppx:pou[@name=$type_name] | \
+                         $all_types/ppx:dataTypes/ppx:dataType[@name=$type_name]""" {
                     with "instance_path" > «$pou_instance_path»
                 }
             }
@@ -91,12 +82,8 @@
             }
             otherwise {
                 variable "type_name" > «@name»
-                apply """exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                         exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                         exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                         exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                         exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                         exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]""" {
+                apply """$all_types/ppx:pous/ppx:pou[@name=$type_name] | \
+                         $all_types/ppx:dataTypes/ppx:dataType[@name=$type_name]""" {
                     with "instance_path" > «$variable_path»
                 }
             }
--- a/plcopen/pou_block_instances.xslt	Mon Feb 19 19:36:43 2018 +0300
+++ b/plcopen/pou_block_instances.xslt	Fri Mar 02 17:01:25 2018 +0100
@@ -1,24 +1,15 @@
 <?xml version="1.0"?>
-<xsl:stylesheet xmlns:func="http://exslt.org/functions" xmlns:dyn="http://exslt.org/dynamic" xmlns:str="http://exslt.org/strings" xmlns:math="http://exslt.org/math" xmlns:exsl="http://exslt.org/common" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:yml="http://fdik.org/yml" xmlns:set="http://exslt.org/sets" xmlns:ppx="http://www.plcopen.org/xml/tc6_0201" xmlns:ns="pou_block_instances_ns" xmlns:regexp="http://exslt.org/regular-expressions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
+<xsl:stylesheet xmlns:exsl="http://exslt.org/common" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:ppx="http://www.plcopen.org/xml/tc6_0201" xmlns:ns="beremiz" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
   <xsl:output method="xml"/>
-  <xsl:variable name="space" select="'                                                                                                                                                                                                        '"/>
-  <xsl:param name="autoindent" select="4"/>
-  <xsl:template match="text()">
-    <xsl:param name="_indent" select="0"/>
-  </xsl:template>
+  <xsl:template match="text()"/>
   <xsl:template match="ppx:pou[ppx:body]|ppx:transition[ppx:body]|ppx:action[ppx:body]">
-    <xsl:param name="_indent" select="0"/>
-    <xsl:apply-templates select="ppx:body/*[self::ppx:FBD or self::ppx:LD or self::ppx:SFC]/*">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:body/*[self::ppx:FBD or self::ppx:LD or self::ppx:SFC]/*"/>
   </xsl:template>
   <xsl:template name="add_instance">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="type"/>
     <xsl:value-of select="ns:AddBlockInstance($type, @localId, ppx:position/@x, ppx:position/@y, @width, @height)"/>
   </xsl:template>
   <xsl:template name="execution_order">
-    <xsl:param name="_indent" select="0"/>
     <xsl:choose>
       <xsl:when test="@executionOrderId">
         <xsl:value-of select="@executionOrderId"/>
@@ -29,7 +20,6 @@
     </xsl:choose>
   </xsl:template>
   <xsl:template name="ConnectionInfos">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="type"/>
     <xsl:param name="negated"/>
     <xsl:param name="edge"/>
@@ -37,18 +27,13 @@
     <xsl:value-of select="ns:AddInstanceConnection($type, $formalParameter, $negated, $edge, ppx:relPosition/@x, ppx:relPosition/@y)"/>
   </xsl:template>
   <xsl:template match="ppx:position">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="ns:AddLinkPoint(@x, @y)"/>
   </xsl:template>
   <xsl:template match="ppx:connection">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="ns:AddConnectionLink(@refLocalId, @formalParameter)"/>
-    <xsl:apply-templates select="ppx:position">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:position"/>
   </xsl:template>
   <xsl:template match="ppx:connectionPointIn">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="negated"/>
     <xsl:param name="edge"/>
     <xsl:param name="formalParameter"/>
@@ -66,12 +51,9 @@
         <xsl:value-of select="$formalParameter"/>
       </xsl:with-param>
     </xsl:call-template>
-    <xsl:apply-templates select="ppx:connection">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:connection"/>
   </xsl:template>
   <xsl:template match="ppx:connectionPointOut">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="negated"/>
     <xsl:param name="edge"/>
     <xsl:param name="formalParameter"/>
@@ -91,7 +73,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:connectionPointOutAction">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="ConnectionInfos">
       <xsl:with-param name="type">
         <xsl:text>output</xsl:text>
@@ -99,7 +80,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:comment">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="ns:SetSpecificValues(ppx:content/xhtml:p/text())"/>
     <xsl:call-template name="add_instance">
       <xsl:with-param name="type">
@@ -108,7 +88,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:block">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="execution_order">
       <xsl:call-template name="execution_order"/>
     </xsl:variable>
@@ -120,7 +99,6 @@
     </xsl:call-template>
     <xsl:for-each select="ppx:inputVariables/ppx:variable">
       <xsl:apply-templates select="ppx:connectionPointIn">
-        <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
         <xsl:with-param name="negated" select="@negated"/>
         <xsl:with-param name="edge" select="@edge"/>
         <xsl:with-param name="formalParameter" select="@formalParameter"/>
@@ -128,7 +106,6 @@
     </xsl:for-each>
     <xsl:for-each select="ppx:outputVariables/ppx:variable">
       <xsl:apply-templates select="ppx:connectionPointOut">
-        <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
         <xsl:with-param name="negated" select="@negated"/>
         <xsl:with-param name="edge" select="@edge"/>
         <xsl:with-param name="formalParameter" select="@formalParameter"/>
@@ -136,23 +113,18 @@
     </xsl:for-each>
   </xsl:template>
   <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:derived">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="@name"/>
   </xsl:template>
   <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:string">
-    <xsl:param name="_indent" select="0"/>
     <xsl:text>STRING</xsl:text>
   </xsl:template>
   <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:wstring">
-    <xsl:param name="_indent" select="0"/>
     <xsl:text>WSTRING</xsl:text>
   </xsl:template>
   <xsl:template match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/*">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="local-name()"/>
   </xsl:template>
   <xsl:template name="VariableBlockInfos">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="type"/>
     <xsl:variable name="expression">
       <xsl:value-of select="ppx:expression/text()"/>
@@ -163,14 +135,10 @@
           <xsl:text>BOOL</xsl:text>
         </xsl:when>
         <xsl:when test="ancestor::ppx:pou[@name=$expression]">
-          <xsl:apply-templates select="ancestor::ppx:pou/child::ppx:interface/ppx:returnType">
-            <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-          </xsl:apply-templates>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:apply-templates select="ancestor::ppx:pou/child::ppx:interface/*/ppx:variable[@name=$expression]/ppx:type">
-            <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-          </xsl:apply-templates>
+          <xsl:apply-templates select="ancestor::ppx:pou/child::ppx:interface/ppx:returnType"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:apply-templates select="ancestor::ppx:pou/child::ppx:interface/*/ppx:variable[@name=$expression]/ppx:type"/>
         </xsl:otherwise>
       </xsl:choose>
     </xsl:variable>
@@ -184,51 +152,40 @@
       </xsl:with-param>
     </xsl:call-template>
     <xsl:apply-templates select="ppx:connectionPointIn">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="negated" select="@negatedIn"/>
       <xsl:with-param name="edge" select="@edgeIn"/>
     </xsl:apply-templates>
     <xsl:apply-templates select="ppx:connectionPointOut">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="negated" select="@negatedOut"/>
       <xsl:with-param name="edge" select="@edgeOut"/>
     </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="ppx:inVariable">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="VariableBlockInfos">
       <xsl:with-param name="type" select="'input'"/>
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:outVariable">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="VariableBlockInfos">
       <xsl:with-param name="type" select="'output'"/>
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:inOutVariable">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="VariableBlockInfos">
       <xsl:with-param name="type" select="'inout'"/>
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:connector|ppx:continuation">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="ns:SetSpecificValues(@name)"/>
     <xsl:call-template name="add_instance">
       <xsl:with-param name="type">
         <xsl:value-of select="local-name()"/>
       </xsl:with-param>
     </xsl:call-template>
-    <xsl:apply-templates select="ppx:connectionPointIn">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
-    <xsl:apply-templates select="ppx:connectionPointOut">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:connectionPointIn"/>
+    <xsl:apply-templates select="ppx:connectionPointOut"/>
   </xsl:template>
   <xsl:template match="ppx:leftPowerRail|ppx:rightPowerRail">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="type" select="local-name()"/>
     <xsl:variable name="connectors">
       <xsl:choose>
@@ -248,19 +205,14 @@
     </xsl:call-template>
     <xsl:choose>
       <xsl:when test="$type='leftPowerRail'">
-        <xsl:apply-templates select="ppx:connectionPointOut">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-        </xsl:apply-templates>
+        <xsl:apply-templates select="ppx:connectionPointOut"/>
       </xsl:when>
       <xsl:otherwise>
-        <xsl:apply-templates select="ppx:connectionPointIn">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-        </xsl:apply-templates>
+        <xsl:apply-templates select="ppx:connectionPointIn"/>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:template>
   <xsl:template match="ppx:contact|ppx:coil">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="type" select="local-name()"/>
     <xsl:variable name="storage">
       <xsl:choose>
@@ -278,18 +230,12 @@
         <xsl:value-of select="$type"/>
       </xsl:with-param>
     </xsl:call-template>
-    <xsl:apply-templates select="ppx:connectionPointIn">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
-    <xsl:apply-templates select="ppx:connectionPointOut">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:connectionPointIn"/>
+    <xsl:apply-templates select="ppx:connectionPointOut"/>
   </xsl:template>
   <xsl:template match="ppx:step">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="ns:SetSpecificValues(@name, @initialStep)"/>
     <xsl:apply-templates select="ppx:connectionPointOutAction">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="negated" select="@negated"/>
     </xsl:apply-templates>
     <xsl:call-template name="add_instance">
@@ -297,15 +243,10 @@
         <xsl:value-of select="local-name()"/>
       </xsl:with-param>
     </xsl:call-template>
-    <xsl:apply-templates select="ppx:connectionPointIn">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
-    <xsl:apply-templates select="ppx:connectionPointOut">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:connectionPointIn"/>
+    <xsl:apply-templates select="ppx:connectionPointOut"/>
   </xsl:template>
   <xsl:template match="ppx:transition">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="priority">
       <xsl:choose>
         <xsl:when test="@priority">
@@ -341,7 +282,6 @@
     </xsl:variable>
     <xsl:value-of select="ns:SetSpecificValues($priority, $condition_type, $condition)"/>
     <xsl:apply-templates select="ppx:condition/ppx:connectionPointIn">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="negated" select="ppx:condition/@negated"/>
     </xsl:apply-templates>
     <xsl:call-template name="add_instance">
@@ -349,15 +289,10 @@
         <xsl:value-of select="local-name()"/>
       </xsl:with-param>
     </xsl:call-template>
-    <xsl:apply-templates select="ppx:connectionPointIn">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
-    <xsl:apply-templates select="ppx:connectionPointOut">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:connectionPointIn"/>
+    <xsl:apply-templates select="ppx:connectionPointOut"/>
   </xsl:template>
   <xsl:template match="ppx:selectionDivergence|ppx:selectionConvergence|ppx:simultaneousDivergence|ppx:simultaneousConvergence">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="type">
       <xsl:value-of select="local-name()"/>
     </xsl:variable>
@@ -377,15 +312,10 @@
         <xsl:value-of select="$type"/>
       </xsl:with-param>
     </xsl:call-template>
-    <xsl:apply-templates select="ppx:connectionPointIn">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
-    <xsl:apply-templates select="ppx:connectionPointOut">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:connectionPointIn"/>
+    <xsl:apply-templates select="ppx:connectionPointOut"/>
   </xsl:template>
   <xsl:template match="ppx:jumpStep">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="type">
       <xsl:text>jump</xsl:text>
     </xsl:variable>
@@ -395,12 +325,9 @@
         <xsl:value-of select="$type"/>
       </xsl:with-param>
     </xsl:call-template>
-    <xsl:apply-templates select="ppx:connectionPointIn">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:connectionPointIn"/>
   </xsl:template>
   <xsl:template match="ppx:action">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="type">
       <xsl:choose>
         <xsl:when test="ppx:reference">
@@ -434,18 +361,14 @@
     <xsl:value-of select="ns:AddAction($qualifier, $type, $value, @duration, @indicator)"/>
   </xsl:template>
   <xsl:template match="ppx:actionBlock">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="ns:SetSpecificValues()"/>
-    <xsl:apply-templates select="ppx:action">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:action"/>
     <xsl:call-template name="add_instance">
       <xsl:with-param name="type">
         <xsl:value-of select="local-name()"/>
       </xsl:with-param>
     </xsl:call-template>
     <xsl:apply-templates select="ppx:connectionPointIn">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
       <xsl:with-param name="negated" select="@negated"/>
     </xsl:apply-templates>
   </xsl:template>
--- a/plcopen/pou_block_instances.ysl2	Mon Feb 19 19:36:43 2018 +0300
+++ b/plcopen/pou_block_instances.ysl2	Fri Mar 02 17:01:25 2018 +0100
@@ -1,7 +1,7 @@
-include yslt.yml2
-estylesheet xmlns:ppx="http://www.plcopen.org/xml/tc6_0201"
+include yslt_noindent.yml2
+istylesheet xmlns:ppx="http://www.plcopen.org/xml/tc6_0201"
             xmlns:xhtml="http://www.w3.org/1999/xhtml"
-            xmlns:ns="pou_block_instances_ns" 
+            xmlns:ns="beremiz" 
             extension-element-prefixes="ns" 
             exclude-result-prefixes="ns" {
     
@@ -312,4 +312,4 @@
             with "negated", "@negated";
         }
     }
-}
\ No newline at end of file
+}
--- a/plcopen/pou_variables.xslt	Mon Feb 19 19:36:43 2018 +0300
+++ b/plcopen/pou_variables.xslt	Fri Mar 02 17:01:25 2018 +0100
@@ -1,34 +1,16 @@
 <?xml version="1.0"?>
-<xsl:stylesheet xmlns:func="http://exslt.org/functions" xmlns:dyn="http://exslt.org/dynamic" xmlns:str="http://exslt.org/strings" xmlns:math="http://exslt.org/math" xmlns:exsl="http://exslt.org/common" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:yml="http://fdik.org/yml" xmlns:set="http://exslt.org/sets" xmlns:ppx="http://www.plcopen.org/xml/tc6_0201" xmlns:ns="pou_vars_ns" xmlns:regexp="http://exslt.org/regular-expressions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
+<xsl:stylesheet xmlns:exsl="http://exslt.org/common" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:ppx="http://www.plcopen.org/xml/tc6_0201" xmlns:ns="beremiz" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
   <xsl:output method="xml"/>
-  <xsl:variable name="space" select="'                                                                                                                                                                                                        '"/>
-  <xsl:param name="autoindent" select="4"/>
-  <xsl:template match="text()">
-    <xsl:param name="_indent" select="0"/>
-  </xsl:template>
-  <xsl:template mode="var_class" match="text()">
-    <xsl:param name="_indent" select="0"/>
-  </xsl:template>
-  <xsl:template mode="var_type" match="text()">
-    <xsl:param name="_indent" select="0"/>
-  </xsl:template>
-  <xsl:template mode="var_edit" match="text()">
-    <xsl:param name="_indent" select="0"/>
-  </xsl:template>
-  <xsl:template mode="var_debug" match="text()">
-    <xsl:param name="_indent" select="0"/>
-  </xsl:template>
-  <xsl:variable name="project">
-    <xsl:copy-of select="document('project')/project/*"/>
-  </xsl:variable>
-  <xsl:variable name="stdlib">
-    <xsl:copy-of select="document('stdlib')/stdlib/*"/>
-  </xsl:variable>
-  <xsl:variable name="extensions">
-    <xsl:copy-of select="document('extensions')/extensions/*"/>
-  </xsl:variable>
+  <xsl:template match="text()"/>
+  <xsl:template mode="var_class" match="text()"/>
+  <xsl:template mode="var_type" match="text()"/>
+  <xsl:template mode="var_edit" match="text()"/>
+  <xsl:template mode="var_debug" match="text()"/>
+  <xsl:variable name="project" select="ns:GetProject()"/>
+  <xsl:variable name="stdlib" select="ns:GetStdLibs()"/>
+  <xsl:variable name="extensions" select="ns:GetExtensions()"/>
+  <xsl:variable name="all_types" select="($project | $stdlib | $extensions)/ppx:types"/>
   <xsl:template name="add_root">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="class"/>
     <xsl:param name="type"/>
     <xsl:param name="edit">
@@ -40,7 +22,6 @@
     <xsl:value-of select="ns:SetRoot($class, $type, $edit, $debug)"/>
   </xsl:template>
   <xsl:template match="ppx:pou">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="add_root">
       <xsl:with-param name="class">
         <xsl:value-of select="@pouType"/>
@@ -49,37 +30,26 @@
         <xsl:value-of select="@name"/>
       </xsl:with-param>
     </xsl:call-template>
-    <xsl:apply-templates select="ppx:interface">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
-    <xsl:apply-templates mode="variable_list" select="ppx:actions/ppx:action | ppx:transitions/ppx:transition">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:interface"/>
+    <xsl:apply-templates mode="variable_list" select="ppx:actions/ppx:action | ppx:transitions/ppx:transition"/>
   </xsl:template>
   <xsl:template match="ppx:action">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="add_root">
       <xsl:with-param name="class">
         <xsl:text>action</xsl:text>
       </xsl:with-param>
     </xsl:call-template>
-    <xsl:apply-templates select="ancestor::ppx:pou/child::ppx:interface">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ancestor::ppx:pou/child::ppx:interface"/>
   </xsl:template>
   <xsl:template match="ppx:transition">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="add_root">
       <xsl:with-param name="class">
         <xsl:text>transition</xsl:text>
       </xsl:with-param>
     </xsl:call-template>
-    <xsl:apply-templates select="ancestor::ppx:pou/child::ppx:interface">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ancestor::ppx:pou/child::ppx:interface"/>
   </xsl:template>
   <xsl:template match="ppx:configuration">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="add_root">
       <xsl:with-param name="class">
         <xsl:text>configuration</xsl:text>
@@ -88,15 +58,10 @@
         <xsl:text>false</xsl:text>
       </xsl:with-param>
     </xsl:call-template>
-    <xsl:apply-templates mode="variable_list" select="ppx:resource">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
-    <xsl:apply-templates select="ppx:globalVars">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates mode="variable_list" select="ppx:resource"/>
+    <xsl:apply-templates select="ppx:globalVars"/>
   </xsl:template>
   <xsl:template match="ppx:resource">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="add_root">
       <xsl:with-param name="class">
         <xsl:text>resource</xsl:text>
@@ -105,45 +70,32 @@
         <xsl:text>false</xsl:text>
       </xsl:with-param>
     </xsl:call-template>
-    <xsl:apply-templates mode="variable_list" select="ppx:pouInstance | ppx:task/ppx:pouInstance">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
-    <xsl:apply-templates select="ppx:globalVars">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates mode="variable_list" select="ppx:pouInstance | ppx:task/ppx:pouInstance"/>
+    <xsl:apply-templates select="ppx:globalVars"/>
   </xsl:template>
   <xsl:template name="variables_infos">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="var_class"/>
     <xsl:for-each select="ppx:variable">
       <xsl:variable name="class">
         <xsl:apply-templates mode="var_class" select="ppx:type">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
           <xsl:with-param name="default_class">
             <xsl:value-of select="$var_class"/>
           </xsl:with-param>
         </xsl:apply-templates>
       </xsl:variable>
       <xsl:variable name="type">
-        <xsl:apply-templates mode="var_type" select="ppx:type">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-        </xsl:apply-templates>
+        <xsl:apply-templates mode="var_type" select="ppx:type"/>
       </xsl:variable>
       <xsl:variable name="edit">
-        <xsl:apply-templates mode="var_edit" select="ppx:type">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-        </xsl:apply-templates>
+        <xsl:apply-templates mode="var_edit" select="ppx:type"/>
       </xsl:variable>
       <xsl:variable name="debug">
-        <xsl:apply-templates mode="var_debug" select="ppx:type">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-        </xsl:apply-templates>
+        <xsl:apply-templates mode="var_debug" select="ppx:type"/>
       </xsl:variable>
       <xsl:value-of select="ns:AddVariable(@name, $class, $type, $edit, $debug)"/>
     </xsl:for-each>
   </xsl:template>
   <xsl:template match="ppx:localVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>Local</xsl:text>
@@ -151,7 +103,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:globalVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>Global</xsl:text>
@@ -159,7 +110,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:externalVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>External</xsl:text>
@@ -167,7 +117,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:tempVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>Temp</xsl:text>
@@ -175,7 +124,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:inputVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>Input</xsl:text>
@@ -183,7 +131,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:outputVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>Output</xsl:text>
@@ -191,7 +138,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:inOutVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>InOut</xsl:text>
@@ -199,7 +145,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template name="add_variable">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="name"/>
     <xsl:param name="class"/>
     <xsl:param name="type"/>
@@ -212,7 +157,6 @@
     <xsl:value-of select="ns:AddVariable($name, $class, $type, $edit, $debug)"/>
   </xsl:template>
   <xsl:template mode="variable_list" match="ppx:action">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="add_variable">
       <xsl:with-param name="name">
         <xsl:value-of select="@name"/>
@@ -223,7 +167,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template mode="variable_list" match="ppx:transition">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="add_variable">
       <xsl:with-param name="name">
         <xsl:value-of select="@name"/>
@@ -234,7 +177,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template mode="variable_list" match="ppx:resource">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="add_variable">
       <xsl:with-param name="name">
         <xsl:value-of select="@name"/>
@@ -248,7 +190,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template mode="variable_list" match="ppx:pouInstance">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="add_variable">
       <xsl:with-param name="name">
         <xsl:value-of select="@name"/>
@@ -262,17 +203,12 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template mode="var_class" match="*[self::ppx:type or self::ppx:baseType]/ppx:derived">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="default_class"/>
     <xsl:variable name="type_name" select="@name"/>
-    <xsl:variable name="pou_infos">
-      <xsl:copy-of select="exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                    exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                    exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]"/>
-    </xsl:variable>
+    <xsl:variable name="pou_infos" select="$all_types/ppx:pous/ppx:pou[@name=$type_name]"/>
     <xsl:choose>
-      <xsl:when test="$pou_infos != ''">
-        <xsl:apply-templates mode="var_class" select="exsl:node-set($pou_infos)">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-        </xsl:apply-templates>
+      <xsl:when test="$pou_infos">
+        <xsl:apply-templates mode="var_class" select="$pou_infos"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:value-of select="$default_class"/>
@@ -280,20 +216,16 @@
     </xsl:choose>
   </xsl:template>
   <xsl:template mode="var_class" match="ppx:pou">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="@pouType"/>
   </xsl:template>
   <xsl:template mode="var_class" match="*[self::ppx:type or self::ppx:baseType]/*">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="default_class"/>
     <xsl:value-of select="$default_class"/>
   </xsl:template>
   <xsl:template mode="var_type" match="*[self::ppx:type or self::ppx:baseType]/ppx:derived">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="@name"/>
   </xsl:template>
   <xsl:template mode="var_type" match="*[self::ppx:type or self::ppx:baseType]/ppx:array">
-    <xsl:param name="_indent" select="0"/>
     <xsl:text>ARRAY [</xsl:text>
     <xsl:for-each select="ppx:dimension">
       <xsl:value-of select="@lower"/>
@@ -301,30 +233,22 @@
       <xsl:value-of select="@upper"/>
     </xsl:for-each>
     <xsl:text>] OF </xsl:text>
-    <xsl:apply-templates mode="var_type" select="ppx:baseType">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates mode="var_type" select="ppx:baseType"/>
   </xsl:template>
   <xsl:template mode="var_type" match="*[self::ppx:type or self::ppx:baseType]/ppx:string">
-    <xsl:param name="_indent" select="0"/>
     <xsl:text>STRING</xsl:text>
   </xsl:template>
   <xsl:template mode="var_type" match="*[self::ppx:type or self::ppx:baseType]/ppx:wstring">
-    <xsl:param name="_indent" select="0"/>
     <xsl:text>WSTRING</xsl:text>
   </xsl:template>
   <xsl:template mode="var_type" match="*[self::ppx:type or self::ppx:baseType]/*">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="local-name()"/>
   </xsl:template>
   <xsl:template mode="var_edit" match="*[self::ppx:type or self::ppx:baseType]/ppx:derived">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="type_name" select="@name"/>
-    <xsl:variable name="pou_infos">
-      <xsl:copy-of select="exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]"/>
-    </xsl:variable>
+    <xsl:variable name="pou_infos" select="$project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]"/>
     <xsl:choose>
-      <xsl:when test="$pou_infos != ''">
+      <xsl:when test="$pou_infos">
         <xsl:text>true</xsl:text>
       </xsl:when>
       <xsl:otherwise>
@@ -333,26 +257,17 @@
     </xsl:choose>
   </xsl:template>
   <xsl:template mode="var_edit" match="*[self::ppx:type or self::ppx:baseType]/ppx:array">
-    <xsl:param name="_indent" select="0"/>
-    <xsl:apply-templates mode="var_edit" select="ppx:baseType">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates mode="var_edit" select="ppx:baseType"/>
   </xsl:template>
   <xsl:template mode="var_edit" match="*[self::ppx:type or self::ppx:baseType]/*">
-    <xsl:param name="_indent" select="0"/>
     <xsl:text>false</xsl:text>
   </xsl:template>
   <xsl:template mode="var_debug" match="*[self::ppx:type or self::ppx:baseType]/ppx:derived">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="type_name" select="@name"/>
-    <xsl:variable name="datatype_infos">
-      <xsl:copy-of select="exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                    exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                    exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                    exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]"/>
-    </xsl:variable>
+    <xsl:variable name="datatype_infos" select="             $project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |             $all_types/ppx:dataTypes/ppx:dataType[@name=$type_name]         "/>
     <xsl:choose>
-      <xsl:when test="$datatype_infos != ''">
-        <xsl:apply-templates mode="var_debug" select="exsl:node-set($datatype_infos)">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-        </xsl:apply-templates>
+      <xsl:when test="$datatype_infos">
+        <xsl:apply-templates mode="var_debug" select="$datatype_infos"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:text>false</xsl:text>
@@ -360,19 +275,15 @@
     </xsl:choose>
   </xsl:template>
   <xsl:template mode="var_debug" match="ppx:pou">
-    <xsl:param name="_indent" select="0"/>
     <xsl:text>true</xsl:text>
   </xsl:template>
   <xsl:template mode="var_debug" match="*[self::ppx:type or self::ppx:baseType]/ppx:array">
-    <xsl:param name="_indent" select="0"/>
     <xsl:text>false</xsl:text>
   </xsl:template>
   <xsl:template mode="var_debug" match="*[self::ppx:type or self::ppx:baseType]/ppx:struct">
-    <xsl:param name="_indent" select="0"/>
     <xsl:text>false</xsl:text>
   </xsl:template>
   <xsl:template mode="var_debug" match="*[self::ppx:type or self::ppx:baseType]/*">
-    <xsl:param name="_indent" select="0"/>
     <xsl:text>true</xsl:text>
   </xsl:template>
 </xsl:stylesheet>
--- a/plcopen/pou_variables.ysl2	Mon Feb 19 19:36:43 2018 +0300
+++ b/plcopen/pou_variables.ysl2	Fri Mar 02 17:01:25 2018 +0100
@@ -1,7 +1,7 @@
-include yslt.yml2
-estylesheet xmlns:ppx="http://www.plcopen.org/xml/tc6_0201"
+include yslt_noindent.yml2
+istylesheet xmlns:ppx="http://www.plcopen.org/xml/tc6_0201"
             xmlns:xhtml="http://www.w3.org/1999/xhtml"
-            xmlns:ns="pou_vars_ns" 
+            xmlns:ns="beremiz" 
             extension-element-prefixes="ns" 
             exclude-result-prefixes="ns" {
     
@@ -11,16 +11,13 @@
     template "text()", mode="var_edit";
     template "text()", mode="var_debug";
     
-    variable "project" {
-        copy "document('project')/project/*";
-    }
-    
-    variable "stdlib" {
-        copy "document('stdlib')/stdlib/*";
-    }
-    variable "extensions" {
-        copy "document('extensions')/extensions/*";
-    }
+    variable "project", "ns:GetProject()";
+    
+    variable "stdlib", "ns:GetStdLibs()";
+
+    variable "extensions", "ns:GetExtensions()";
+
+    variable "all_types", "($project | $stdlib | $extensions)/ppx:types";
     
     function "add_root" {
         param "class";
@@ -176,14 +173,10 @@
     template "*[self::ppx:type or self::ppx:baseType]/ppx:derived", mode="var_class" {
         param "default_class";
         variable "type_name", "@name";
-        variable "pou_infos" {
-            copy """exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                    exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                    exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]""";
-        }
+        variable "pou_infos", "$all_types/ppx:pous/ppx:pou[@name=$type_name]";
         choose {
-            when "$pou_infos != ''" {
-                apply "exsl:node-set($pou_infos)", mode="var_class";
+            when "$pou_infos" {
+                apply "$pou_infos", mode="var_class";
             }
             otherwise {
                 value "$default_class"
@@ -227,11 +220,9 @@
     
     template "*[self::ppx:type or self::ppx:baseType]/ppx:derived", mode="var_edit" {
         variable "type_name", "@name";
-        variable "pou_infos" {
-            copy "exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]";
-        }
+        variable "pou_infos", "$project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]";
         choose {
-            when "$pou_infos != ''" > true
+            when "$pou_infos" > true
             otherwise > false
         }
     }
@@ -246,15 +237,13 @@
     
     template "*[self::ppx:type or self::ppx:baseType]/ppx:derived", mode="var_debug" {
         variable "type_name", "@name";
-        variable "datatype_infos" {
-            copy """exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                    exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                    exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                    exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]""";
-        }
+        variable "datatype_infos", """ \
+            $project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] | \
+            $all_types/ppx:dataTypes/ppx:dataType[@name=$type_name] \
+        """;
         choose {
-            when "$datatype_infos != ''" {
-                apply "exsl:node-set($datatype_infos)", mode="var_debug";
+            when "$datatype_infos" {
+                apply "$datatype_infos", mode="var_debug";
             }
             otherwise > false
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plcopen/types_enums.py	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,131 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# This file is part of Beremiz
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+from util.TranslationCatalogs import NoTranslate
+_ = NoTranslate
+
+ITEMS_EDITABLE = [
+    ITEM_PROJECT,
+    ITEM_POU,
+    ITEM_VARIABLE,
+    ITEM_TRANSITION,
+    ITEM_ACTION,
+    ITEM_CONFIGURATION,
+    ITEM_RESOURCE,
+    ITEM_DATATYPE
+] = range(8)
+
+ITEMS_UNEDITABLE = [
+    ITEM_DATATYPES,
+    ITEM_FUNCTION,
+    ITEM_FUNCTIONBLOCK,
+    ITEM_PROGRAM,
+    ITEM_TRANSITIONS,
+    ITEM_ACTIONS,
+    ITEM_CONFIGURATIONS,
+    ITEM_RESOURCES,
+    ITEM_PROPERTIES
+] = range(8, 17)
+
+ITEMS_VARIABLE = [
+    ITEM_VAR_LOCAL,
+    ITEM_VAR_GLOBAL,
+    ITEM_VAR_EXTERNAL,
+    ITEM_VAR_TEMP,
+    ITEM_VAR_INPUT,
+    ITEM_VAR_OUTPUT,
+    ITEM_VAR_INOUT
+] = range(17, 24)
+
+ITEM_CONFNODE = 25
+
+VAR_CLASS_INFOS = {
+    "Local":    ("localVars",    ITEM_VAR_LOCAL),
+    "Global":   ("globalVars",   ITEM_VAR_GLOBAL),
+    "External": ("externalVars", ITEM_VAR_EXTERNAL),
+    "Temp":     ("tempVars",     ITEM_VAR_TEMP),
+    "Input":    ("inputVars",    ITEM_VAR_INPUT),
+    "Output":   ("outputVars",   ITEM_VAR_OUTPUT),
+    "InOut":    ("inOutVars",    ITEM_VAR_INOUT)}
+
+POU_TYPES = {
+    "program": ITEM_PROGRAM,
+    "functionBlock": ITEM_FUNCTIONBLOCK,
+    "function": ITEM_FUNCTION,
+}
+
+CLASS_TYPES = {
+    "configuration": ITEM_CONFIGURATION,
+    "resource": ITEM_RESOURCE,
+    "action": ITEM_ACTION,
+    "transition": ITEM_TRANSITION,
+    "program": ITEM_PROGRAM
+}
+
+LOCATIONS_ITEMS = [LOCATION_CONFNODE,
+                   LOCATION_MODULE,
+                   LOCATION_GROUP,
+                   LOCATION_VAR_INPUT,
+                   LOCATION_VAR_OUTPUT,
+                   LOCATION_VAR_MEMORY] = range(6)
+
+UNEDITABLE_NAMES = [_("User-defined POUs"), _("Functions"), _("Function Blocks"),
+                    _("Programs"), _("Data Types"), _("Transitions"), _("Actions"),
+                    _("Configurations"), _("Resources"), _("Properties")]
+
+[USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS,
+ DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS,
+ RESOURCES, PROPERTIES] = UNEDITABLE_NAMES
+
+# -------------------------------------------------------------------------------
+#                   Project Element tag name computation functions
+# -------------------------------------------------------------------------------
+
+
+# Compute a data type name
+def ComputeDataTypeName(datatype):
+    return "D::%s" % datatype
+
+
+# Compute a pou name
+def ComputePouName(pou):
+    return "P::%s" % pou
+
+
+# Compute a pou transition name
+def ComputePouTransitionName(pou, transition):
+    return "T::%s::%s" % (pou, transition)
+
+
+# Compute a pou action name
+def ComputePouActionName(pou, action):
+    return "A::%s::%s" % (pou, action)
+
+
+# Compute a pou  name
+def ComputeConfigurationName(config):
+    return "C::%s" % config
+
+
+# Compute a pou  name
+def ComputeConfigurationResourceName(config, resource):
+    return "R::%s::%s" % (config, resource)
+
+
+def GetElementType(tagname):
+    words = tagname.split("::")
+    return {
+        "D": ITEM_DATATYPE,
+        "P": ITEM_POU,
+        "T": ITEM_TRANSITION,
+        "A": ITEM_ACTION,
+        "C": ITEM_CONFIGURATION,
+        "R": ITEM_RESOURCE
+    }[words[0]]
+
+
+# remove gettext override
+del _
--- a/plcopen/variables_infos.xslt	Mon Feb 19 19:36:43 2018 +0300
+++ b/plcopen/variables_infos.xslt	Fri Mar 02 17:01:25 2018 +0100
@@ -1,48 +1,26 @@
 <?xml version="1.0"?>
-<xsl:stylesheet xmlns:func="http://exslt.org/functions" xmlns:dyn="http://exslt.org/dynamic" xmlns:str="http://exslt.org/strings" xmlns:math="http://exslt.org/math" xmlns:exsl="http://exslt.org/common" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:yml="http://fdik.org/yml" xmlns:set="http://exslt.org/sets" xmlns:ppx="http://www.plcopen.org/xml/tc6_0201" xmlns:ns="var_infos_ns" xmlns:regexp="http://exslt.org/regular-expressions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
+<xsl:stylesheet xmlns:exsl="http://exslt.org/common" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:ppx="http://www.plcopen.org/xml/tc6_0201" xmlns:ns="beremiz" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
   <xsl:output method="xml"/>
-  <xsl:variable name="space" select="'                                                                                                                                                                                                        '"/>
-  <xsl:param name="autoindent" select="4"/>
   <xsl:param name="tree"/>
-  <xsl:template match="text()">
-    <xsl:param name="_indent" select="0"/>
-  </xsl:template>
-  <xsl:variable name="project">
-    <xsl:copy-of select="document('project')/project/*"/>
-  </xsl:variable>
-  <xsl:variable name="stdlib">
-    <xsl:copy-of select="document('stdlib')/stdlib/*"/>
-  </xsl:variable>
-  <xsl:variable name="extensions">
-    <xsl:copy-of select="document('extensions')/extensions/*"/>
-  </xsl:variable>
+  <xsl:template match="text()"/>
+  <xsl:variable name="project" select="ns:GetProject()"/>
+  <xsl:variable name="stdlib" select="ns:GetStdLibs()"/>
+  <xsl:variable name="extensions" select="ns:GetExtensions()"/>
+  <xsl:variable name="all_types" select="($project | $stdlib | $extensions)/ppx:types"/>
   <xsl:template match="ppx:configuration">
-    <xsl:param name="_indent" select="0"/>
-    <xsl:apply-templates select="ppx:globalVars">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:globalVars"/>
   </xsl:template>
   <xsl:template match="ppx:resource">
-    <xsl:param name="_indent" select="0"/>
-    <xsl:apply-templates select="ppx:globalVars">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:globalVars"/>
   </xsl:template>
   <xsl:template match="ppx:pou">
-    <xsl:param name="_indent" select="0"/>
-    <xsl:apply-templates select="ppx:interface/*">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates select="ppx:interface/*"/>
   </xsl:template>
   <xsl:template match="ppx:returnType">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="ns:AddTree()"/>
-    <xsl:apply-templates mode="var_type" select=".">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates mode="var_type" select="."/>
   </xsl:template>
   <xsl:template name="variables_infos">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="var_class"/>
     <xsl:variable name="var_option">
       <xsl:choose>
@@ -59,9 +37,7 @@
     </xsl:variable>
     <xsl:for-each select="ppx:variable">
       <xsl:variable name="initial_value">
-        <xsl:apply-templates select="ppx:initialValue">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-        </xsl:apply-templates>
+        <xsl:apply-templates select="ppx:initialValue"/>
       </xsl:variable>
       <xsl:variable name="edit">
         <xsl:choose>
@@ -69,21 +45,16 @@
             <xsl:text>true</xsl:text>
           </xsl:when>
           <xsl:otherwise>
-            <xsl:apply-templates mode="var_edit" select="ppx:type">
-              <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-            </xsl:apply-templates>
+            <xsl:apply-templates mode="var_edit" select="ppx:type"/>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:variable>
       <xsl:value-of select="ns:AddTree()"/>
-      <xsl:apply-templates mode="var_type" select="ppx:type">
-        <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-      </xsl:apply-templates>
+      <xsl:apply-templates mode="var_type" select="ppx:type"/>
       <xsl:value-of select="ns:AddVariable(@name, $var_class, $var_option, @address, $initial_value, $edit, ppx:documentation/xhtml:p/text())"/>
     </xsl:for-each>
   </xsl:template>
   <xsl:template match="ppx:localVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>Local</xsl:text>
@@ -91,7 +62,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:globalVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>Global</xsl:text>
@@ -99,7 +69,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:externalVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>External</xsl:text>
@@ -107,7 +76,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:tempVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>Temp</xsl:text>
@@ -115,7 +83,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:inputVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>Input</xsl:text>
@@ -123,7 +90,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:outputVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>Output</xsl:text>
@@ -131,7 +97,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:inOutVars">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="variables_infos">
       <xsl:with-param name="var_class">
         <xsl:text>InOut</xsl:text>
@@ -139,53 +104,35 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template mode="var_type" match="ppx:pou">
-    <xsl:param name="_indent" select="0"/>
-    <xsl:apply-templates mode="var_type" select="ppx:interface/*[self::ppx:inputVars or self::ppx:inOutVars or self::ppx:outputVars]/ppx:variable">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates mode="var_type" select="ppx:interface/*[self::ppx:inputVars or self::ppx:inOutVars or self::ppx:outputVars]/ppx:variable"/>
   </xsl:template>
   <xsl:template mode="var_type" match="ppx:variable">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="name">
       <xsl:value-of select="@name"/>
     </xsl:variable>
     <xsl:value-of select="ns:AddTree()"/>
-    <xsl:apply-templates mode="var_type" select="ppx:type">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates mode="var_type" select="ppx:type"/>
     <xsl:value-of select="ns:AddVarToTree($name)"/>
   </xsl:template>
   <xsl:template mode="var_type" match="ppx:dataType">
-    <xsl:param name="_indent" select="0"/>
-    <xsl:apply-templates mode="var_type" select="ppx:baseType">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates mode="var_type" select="ppx:baseType"/>
   </xsl:template>
   <xsl:template mode="var_type" match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:struct">
-    <xsl:param name="_indent" select="0"/>
-    <xsl:apply-templates mode="var_type" select="ppx:variable">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates mode="var_type" select="ppx:variable"/>
   </xsl:template>
   <xsl:template mode="var_type" match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:derived">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="type_name">
       <xsl:value-of select="@name"/>
     </xsl:variable>
     <xsl:choose>
       <xsl:when test="$tree='True'">
-        <xsl:apply-templates mode="var_type" select="exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                         exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                         exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                         exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |&#10;                         exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                         exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]">
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-        </xsl:apply-templates>
+        <xsl:apply-templates mode="var_type" select="$all_types/ppx:pous/ppx:pou[@name=$type_name] |                          $all_types/ppx:dataTypes/ppx:dataType[@name=$type_name]"/>
       </xsl:when>
     </xsl:choose>
     <xsl:value-of select="ns:SetType($type_name)"/>
   </xsl:template>
   <xsl:template mode="var_type" match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:array">
-    <xsl:param name="_indent" select="0"/>
-    <xsl:apply-templates mode="var_type" select="ppx:baseType">
-      <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-    </xsl:apply-templates>
+    <xsl:apply-templates mode="var_type" select="ppx:baseType"/>
     <xsl:for-each select="ppx:dimension">
       <xsl:variable name="lower">
         <xsl:value-of select="@lower"/>
@@ -197,34 +144,28 @@
     </xsl:for-each>
   </xsl:template>
   <xsl:template mode="var_type" match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:string">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="name">
       <xsl:text>STRING</xsl:text>
     </xsl:variable>
     <xsl:value-of select="ns:SetType($name)"/>
   </xsl:template>
   <xsl:template mode="var_type" match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:wstring">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="name">
       <xsl:text>WSTRING</xsl:text>
     </xsl:variable>
     <xsl:value-of select="ns:SetType($name)"/>
   </xsl:template>
   <xsl:template mode="var_type" match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/*">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="name">
       <xsl:value-of select="local-name()"/>
     </xsl:variable>
     <xsl:value-of select="ns:SetType($name)"/>
   </xsl:template>
   <xsl:template mode="var_edit" match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:derived">
-    <xsl:param name="_indent" select="0"/>
     <xsl:variable name="type_name">
       <xsl:value-of select="@name"/>
     </xsl:variable>
-    <xsl:variable name="pou_infos">
-      <xsl:copy-of select="exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                    exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |&#10;                    exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]"/>
-    </xsl:variable>
+    <xsl:variable name="pou_infos" select="$all_types/ppx:pous/ppx:pou[@name=$type_name]"/>
     <xsl:choose>
       <xsl:when test="$pou_infos != ''">
         <xsl:text>false</xsl:text>
@@ -235,47 +176,35 @@
     </xsl:choose>
   </xsl:template>
   <xsl:template mode="var_edit" match="*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/*">
-    <xsl:param name="_indent" select="0"/>
     <xsl:text>true</xsl:text>
   </xsl:template>
   <xsl:template match="ppx:value">
-    <xsl:param name="_indent" select="0"/>
     <xsl:choose>
       <xsl:when test="@repetitionValue">
         <xsl:value-of select="@repetitionValue"/>
         <xsl:text>(</xsl:text>
-        <xsl:apply-templates>
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-        </xsl:apply-templates>
+        <xsl:apply-templates/>
         <xsl:text>)</xsl:text>
       </xsl:when>
       <xsl:when test="@member">
         <xsl:value-of select="@member"/>
         <xsl:text> := </xsl:text>
-        <xsl:apply-templates>
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-        </xsl:apply-templates>
+        <xsl:apply-templates/>
       </xsl:when>
       <xsl:otherwise>
-        <xsl:apply-templates>
-          <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-        </xsl:apply-templates>
+        <xsl:apply-templates/>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:template>
   <xsl:template match="ppx:simpleValue">
-    <xsl:param name="_indent" select="0"/>
     <xsl:value-of select="@value"/>
   </xsl:template>
   <xsl:template name="complex_type_value">
-    <xsl:param name="_indent" select="0"/>
     <xsl:param name="start_bracket"/>
     <xsl:param name="end_bracket"/>
     <xsl:value-of select="$start_bracket"/>
     <xsl:for-each select="ppx:value">
-      <xsl:apply-templates select=".">
-        <xsl:with-param name="_indent" select="$_indent + (1) * $autoindent"/>
-      </xsl:apply-templates>
+      <xsl:apply-templates select="."/>
       <xsl:choose>
         <xsl:when test="position()!=last()">
           <xsl:text>, </xsl:text>
@@ -285,7 +214,6 @@
     <xsl:value-of select="$end_bracket"/>
   </xsl:template>
   <xsl:template match="ppx:arrayValue">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="complex_type_value">
       <xsl:with-param name="start_bracket">
         <xsl:text>[</xsl:text>
@@ -296,7 +224,6 @@
     </xsl:call-template>
   </xsl:template>
   <xsl:template match="ppx:structValue">
-    <xsl:param name="_indent" select="0"/>
     <xsl:call-template name="complex_type_value">
       <xsl:with-param name="start_bracket">
         <xsl:text>(</xsl:text>
--- a/plcopen/variables_infos.ysl2	Mon Feb 19 19:36:43 2018 +0300
+++ b/plcopen/variables_infos.ysl2	Fri Mar 02 17:01:25 2018 +0100
@@ -1,7 +1,7 @@
-include yslt.yml2
-estylesheet xmlns:ppx="http://www.plcopen.org/xml/tc6_0201"
+include yslt_noindent.yml2
+istylesheet xmlns:ppx="http://www.plcopen.org/xml/tc6_0201"
             xmlns:xhtml="http://www.w3.org/1999/xhtml"
-            xmlns:ns="var_infos_ns" 
+            xmlns:ns="beremiz" 
             extension-element-prefixes="ns" 
             exclude-result-prefixes="ns" {
     
@@ -9,17 +9,14 @@
     
     template "text()";
     
-    variable "project" {
-        copy "document('project')/project/*";
-    }
-    
-    variable "stdlib" {
-        copy "document('stdlib')/stdlib/*";
-    }
-    variable "extensions" {
-        copy "document('extensions')/extensions/*";
-    }
-    
+    variable "project", "ns:GetProject()";
+    
+    variable "stdlib", "ns:GetStdLibs()";
+
+    variable "extensions", "ns:GetExtensions()";
+
+    variable "all_types", "($project | $stdlib | $extensions)/ppx:types";
+
     template "ppx:configuration" {
         apply "ppx:globalVars";
     }
@@ -129,12 +126,8 @@
         variable "type_name" > «@name»
         choose {
             when "$tree='True'" {
-                apply """exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                         exsl:node-set($project)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                         exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                         exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name] |
-                         exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                         exsl:node-set($extensions)/ppx:project/ppx:types/ppx:dataTypes/ppx:dataType[@name=$type_name]""", mode="var_type";
+                apply """$all_types/ppx:pous/ppx:pou[@name=$type_name] | \
+                         $all_types/ppx:dataTypes/ppx:dataType[@name=$type_name]""", mode="var_type";
             }
         }
         value "ns:SetType($type_name)";
@@ -166,11 +159,7 @@
     
     template "*[self::ppx:type or self::ppx:baseType or self::ppx:returnType]/ppx:derived", mode="var_edit" {
         variable "type_name" > «@name»
-        variable "pou_infos" {
-            copy """exsl:node-set($project)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                    exsl:node-set($stdlib)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name] |
-                    exsl:node-set($extensions)/ppx:project/ppx:types/ppx:pous/ppx:pou[@name=$type_name]""";
-        }
+        variable "pou_infos", "$all_types/ppx:pous/ppx:pou[@name=$type_name]";
         choose {
             when "$pou_infos != ''" > false
             otherwise > true
@@ -232,4 +221,4 @@
 }
 
     
-    
\ No newline at end of file
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plcopen/yslt_noindent.yml2	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,32 @@
+include yslt.yml2
+
+in xsl {
+    decl istylesheet (
+        *output="xml",
+        version="1.0",
+        xmlns:xsl="http://www.w3.org/1999/XSL/Transform",
+        xmlns:exsl='http://exslt.org/common',
+        extension-element-prefixes='exsl'
+    ) alias stylesheet {
+        output *output;
+        content;
+    };
+
+    decl template(match) {
+        content;
+    };
+
+    decl function(name) alias template {
+        content;
+    };
+   
+    decl call(name) alias call-template {
+        content;
+    };
+
+    decl apply(select) alias apply-templates {
+        content;
+    };
+}
+
+
--- a/py_ext/PythonFileCTNMixin.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/py_ext/PythonFileCTNMixin.py	Fri Mar 02 17:01:25 2018 +0100
@@ -119,6 +119,7 @@
                 "configname": configname.upper(),
                 "uppername": variable.getname().upper(),
                 "IECtype": variable.gettype(),
+                "initial": repr(variable.getinitial()),
                 "pyextname": pyextname
             },
             self.CodeFile.variables.variable)
@@ -136,6 +137,7 @@
 _%(pyextname)sGlobalsDesc.append((
     "%(name)s",
     "%(IECtype)s",
+    %(initial)s,
     %(desc)s,
     %(onchange)s,
     %(opts)s))
@@ -169,7 +171,7 @@
 ##
 
 ## Code for PLC global variable access
-from targets.typemapping import TypeTranslator
+from runtime.typemapping import TypeTranslator
 import ctypes
 _%(pyextname)sGlobalsDesc = []
 __ext_name__ = "%(pyextname)s"
--- a/runtime/NevowServer.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/runtime/NevowServer.py	Fri Mar 02 17:01:25 2018 +0100
@@ -26,10 +26,10 @@
 from __future__ import absolute_import
 from __future__ import print_function
 import os
-import util.paths as paths
 from nevow import appserver, inevow, tags, loaders, athena
 from nevow.page import renderer
 from twisted.internet import reactor
+import util.paths as paths
 
 xhtml_header = '''<?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
--- a/runtime/PLCObject.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/runtime/PLCObject.py	Fri Mar 02 17:01:25 2018 +0100
@@ -29,17 +29,18 @@
 import sys
 import traceback
 from time import time
-
+import _ctypes  # pylint: disable=wrong-import-order
 import Pyro.core as pyro
 
-from targets.typemapping import LogLevelsDefault, LogLevelsCount, TypeTranslator
-
+from runtime.typemapping import TypeTranslator
+from runtime.loglevels import LogLevelsDefault, LogLevelsCount
 
 if os.name in ("nt", "ce"):
-    from _ctypes import LoadLibrary as dlopen
-    from _ctypes import FreeLibrary as dlclose
+    dlopen = _ctypes.LoadLibrary
+    dlclose = _ctypes.FreeLibrary
 elif os.name == "posix":
-    from _ctypes import dlopen, dlclose
+    dlopen = _ctypes.dlopen
+    dlclose = _ctypes.dlclose
 
 
 def get_last_traceback(tb):
@@ -105,7 +106,10 @@
         else:
             level = LogLevelsDefault
             msg, = args
-        return self._LogMessage(level, msg, len(msg))
+        PLCprint(msg)
+        if self._LogMessage is not None:
+            return self._LogMessage(level, msg, len(msg))
+        return None
 
     def ResetLogCount(self):
         if self._ResetLogCount is not None:
@@ -253,7 +257,7 @@
         self._resumeDebug = lambda: None
         self._PythonIterator = lambda: ""
         self._GetLogCount = None
-        self._LogMessage = lambda l, m, s: PLCprint("OFF LOG :"+m)
+        self._LogMessage = None
         self._GetLogMessage = None
         self.PLClibraryHandle = None
         # Unload library explicitely
--- a/runtime/WampClient.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/runtime/WampClient.py	Fri Mar 02 17:01:25 2018 +0100
@@ -24,11 +24,11 @@
 
 from __future__ import absolute_import
 from __future__ import print_function
+import time
 import json
-
 from autobahn.twisted import wamp
 from autobahn.twisted.websocket import WampWebSocketClientFactory, connectWS
-from autobahn.wamp import types
+from autobahn.wamp import types, auth
 from autobahn.wamp.serializer import MsgPackSerializer
 from twisted.internet.defer import inlineCallbacks
 from twisted.internet.protocol import ReconnectingClientFactory
@@ -51,8 +51,13 @@
     "ResetLogCount",
 ]
 
+# Those two lists are meant to be filled by customized runtime
+# or User python code.
+
+""" crossbar Events to register to """
 SubscribedEvents = []
 
+""" things to do on join (callables) """
 DoOnJoin = []
 
 
@@ -66,6 +71,20 @@
 
 
 class WampSession(wamp.ApplicationSession):
+    def onConnect(self):
+        if "secret" in self.config.extra:
+            user = self.config.extra["ID"].encode('utf8')
+            self.join(u"Automation", [u"wampcra"], user)
+        else:
+            self.join(u"Automation")
+
+    def onChallenge(self, challenge):
+        if challenge.method == u"wampcra":
+            secret = self.config.extra["secret"].encode('utf8')
+            signature = auth.compute_wcs(secret, challenge.extra['challenge'].encode('utf8'))
+            return signature.decode("ascii")
+        else:
+            raise Exception("don't know how to handle authmethod {}".format(challenge.method))
 
     @inlineCallbacks
     def onJoin(self, details):
@@ -74,10 +93,11 @@
         ID = self.config.extra["ID"]
         print('WAMP session joined by :', ID)
         for name in ExposedCalls:
-            yield self.register(GetCallee(name), '.'.join((ID, name)))
+            regoption = types.RegisterOptions(u'exact', u'last')
+            yield self.register(GetCallee(name), u'.'.join((ID, name)), regoption)
 
         for name in SubscribedEvents:
-            yield self.subscribe(GetCallee(name), name)
+            yield self.subscribe(GetCallee(name), unicode(name))
 
         for func in DoOnJoin:
             yield func(self)
@@ -85,36 +105,58 @@
     def onLeave(self, details):
         global _WampSession
         _WampSession = None
-        print('WAMP session left')
+        print(_('WAMP session left'))
 
 
 class ReconnectingWampWebSocketClientFactory(WampWebSocketClientFactory, ReconnectingClientFactory):
     def clientConnectionFailed(self, connector, reason):
-        print("WAMP Client connection failed .. retrying ..")
-        self.retry(connector)
+        print(_("WAMP Client connection failed (%s) .. retrying .." % time.ctime()))
+        ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
 
     def clientConnectionLost(self, connector, reason):
-        print("WAMP Client connection lost .. retrying ..")
-        self.retry(connector)
+        print(_("WAMP Client connection lost (%s) .. retrying .." % time.ctime()))
+        ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
 
 
 def LoadWampClientConf(wampconf):
-
-    WSClientConf = json.load(open(wampconf))
-    return WSClientConf
+    try:
+        WSClientConf = json.load(open(wampconf))
+        return WSClientConf
+    except ValueError, ve:
+        print(_("WAMP load error: "), ve)
+        return None
+    except Exception:
+        return None
 
 
-def RegisterWampClient(wampconf):
+def LoadWampSecret(secretfname):
+    try:
+        WSClientWampSecret = open(secretfname, 'rb').read()
+        return WSClientWampSecret
+    except ValueError, ve:
+        print(_("Wamp secret load error:"), ve)
+        return None
+    except Exception:
+        return None
+
+
+def RegisterWampClient(wampconf, secretfname):
 
     WSClientConf = LoadWampClientConf(wampconf)
 
-    # start logging to console
-    # log.startLogging(sys.stdout)
+    if not WSClientConf:
+        print(_("WAMP client connection not established!"))
+        return
+
+    WampSecret = LoadWampSecret(secretfname)
+
+    if WampSecret is not None:
+        WSClientConf["secret"] = WampSecret
 
     # create a WAMP application session factory
     component_config = types.ComponentConfig(
         realm=WSClientConf["realm"],
-        extra={"ID": WSClientConf["ID"]})
+        extra=WSClientConf)
     session_factory = wamp.ApplicationSessionFactory(
         config=component_config)
     session_factory.session = WampSession
@@ -123,13 +165,11 @@
     transport_factory = ReconnectingWampWebSocketClientFactory(
         session_factory,
         url=WSClientConf["url"],
-        serializers=[MsgPackSerializer()],
-        debug=False,
-        debug_wamp=False)
+        serializers=[MsgPackSerializer()])
 
     # start the client from a Twisted endpoint
     conn = connectWS(transport_factory)
-    print("WAMP client connecting to :", WSClientConf["url"])
+    print(_("WAMP client connecting to :"), WSClientConf["url"])
     return conn
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/loglevels.py	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# See COPYING.Runtime file for copyrights details.
+
+LogLevels = ["CRITICAL", "WARNING", "INFO", "DEBUG"]
+LogLevelsCount = len(LogLevels)
+LogLevelsDict = dict(zip(LogLevels, range(LogLevelsCount)))
+LogLevelsDefault = LogLevelsDict["DEBUG"]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/typemapping.py	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# See COPYING.Runtime file for copyrights details.
+#
+
+from __future__ import absolute_import
+import ctypes
+from ctypes import *
+from datetime import timedelta as td
+
+ctypes.pythonapi.PyString_AsString.argtypes = (ctypes.c_void_p,)
+ctypes.pythonapi.PyString_AsString.restype = ctypes.POINTER(ctypes.c_char)
+
+
+class IEC_STRING(Structure):
+    """
+    Must be changed according to changes in iec_types.h
+    """
+    _fields_ = [("len", c_uint8),
+                ("body", c_char * 126)]
+
+
+class IEC_TIME(Structure):
+    """
+    Must be changed according to changes in iec_types.h
+    """
+    _fields_ = [("s", c_long),   # tv_sec
+                ("ns", c_long)]  # tv_nsec
+
+
+def _t(t, u=lambda x: x.value, p=lambda t, x: t(x)):
+    return (t, u, p)
+
+
+def _ttime():
+    return (IEC_TIME,
+            lambda x: td(0, x.s, x.ns/1000.0),
+            lambda t, x: t(x.days * 24 * 3600 + x.seconds, x.microseconds*1000))
+
+
+SameEndianessTypeTranslator = {
+    "BOOL":       _t(c_uint8, lambda x: x.value != 0),
+    "STEP":       _t(c_uint8),
+    "TRANSITION": _t(c_uint8),
+    "ACTION":     _t(c_uint8),
+    "SINT":       _t(c_int8),
+    "USINT":      _t(c_uint8),
+    "BYTE":       _t(c_uint8),
+    "STRING":     (IEC_STRING,
+                   lambda x: x.body[:x.len],
+                   lambda t, x: t(len(x), x)),
+    "INT":        _t(c_int16),
+    "UINT":       _t(c_uint16),
+    "WORD":       _t(c_uint16),
+    "DINT":       _t(c_int32),
+    "UDINT":      _t(c_uint32),
+    "DWORD":      _t(c_uint32),
+    "LINT":       _t(c_int64),
+    "ULINT":      _t(c_uint64),
+    "LWORD":      _t(c_uint64),
+    "REAL":       _t(c_float),
+    "LREAL":      _t(c_double),
+    "TIME":       _ttime(),
+    "TOD":        _ttime(),
+    "DATE":       _ttime(),
+    "DT":         _ttime(),
+    }
+
+SwapedEndianessTypeTranslator = {
+    # TODO
+    }
+
+TypeTranslator = SameEndianessTypeTranslator
+
+# Construct debugger natively supported types
+DebugTypesSize = dict([(key, sizeof(t)) for key, (t, p, u) in SameEndianessTypeTranslator.iteritems() if t is not None])
+
+
+def UnpackDebugBuffer(buff, indexes):
+    res = []
+    buffoffset = 0
+    buffsize = len(buff)
+    buffptr = cast(ctypes.pythonapi.PyString_AsString(id(buff)), c_void_p).value
+    for iectype in indexes:
+        c_type, unpack_func, _pack_func = \
+            TypeTranslator.get(iectype, (None, None, None))
+        if c_type is not None and buffoffset < buffsize:
+            cursor = c_void_p(buffptr + buffoffset)
+            value = unpack_func(cast(cursor,
+                                     POINTER(c_type)).contents)
+            buffoffset += sizeof(c_type) if iectype != "STRING" else len(value)+1
+            res.append(value)
+        else:
+            break
+    if buffoffset and buffoffset == buffsize:
+        return res
+    return None
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime_files.list	Fri Mar 02 17:01:25 2018 +0100
@@ -0,0 +1,17 @@
+# those files are used in runtime
+# licensed according to LGPL, see COPYING.runtime 
+
+images/icostop24.png
+images/icoplay24.png
+images/brz.png
+util/__init__.py
+util/paths.py
+runtime/WampClient.py
+runtime/PLCObject.py
+runtime/NevowServer.py
+runtime/webinterface.js
+runtime/__init__.py
+runtime/ServicePublisher.py
+runtime/typemapping.py 
+runtime/loglevels.py 
+Beremiz_service.py
--- a/svgui/svgui_server.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/svgui/svgui_server.py	Fri Mar 02 17:01:25 2018 +0100
@@ -27,7 +27,7 @@
 import os
 
 from nevow import tags, loaders
-import simplejson as json
+import simplejson as json  # pylint: disable=import-error
 import runtime.NevowServer as NS
 
 svgfile = '%(svgfile)s'
--- a/targets/Linux/plc_Linux_main.c	Mon Feb 19 19:36:43 2018 +0300
+++ b/targets/Linux/plc_Linux_main.c	Fri Mar 02 17:01:25 2018 +0100
@@ -232,6 +232,7 @@
     pthread_mutex_lock(&python_mutex);
 }
 
+#ifndef HAVE_RETAIN
 void InitRetain(void)
 {
 }
@@ -260,3 +261,4 @@
 void Remind(unsigned int offset, unsigned int count, void *p)
 {
 }
+#endif // !HAVE_RETAIN
--- a/targets/Win32/plc_Win32_main.c	Mon Feb 19 19:36:43 2018 +0300
+++ b/targets/Win32/plc_Win32_main.c	Fri Mar 02 17:01:25 2018 +0100
@@ -241,6 +241,7 @@
 	WaitForSingleObject(python_sem, INFINITE);
 }
 
+#ifndef HAVE_RETAIN
 void InitRetain(void)
 {
 }
@@ -275,6 +276,7 @@
 void Remind(unsigned int offset, unsigned int count, void *p)
 {
 }
+#endif // !HAVE_RETAIN
 
 static void __attribute__((constructor))
 beremiz_dll_init(void)
--- a/targets/Xenomai/plc_Xenomai_main.c	Mon Feb 19 19:36:43 2018 +0300
+++ b/targets/Xenomai/plc_Xenomai_main.c	Fri Mar 02 17:01:25 2018 +0100
@@ -363,6 +363,7 @@
     }    /* as plc does not wait for lock. */
 }
 
+#ifndef HAVE_RETAIN
 int CheckRetainBuffer(void)
 {
 	return 1;
@@ -391,3 +392,4 @@
 void InitRetain(void)
 {
 }
+#endif // !HAVE_RETAIN
--- a/targets/Xenomai/plc_Xenomai_noretain.c	Mon Feb 19 19:36:43 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-int CheckRetainBuffer(void)
-{
-	return 1;
-}
-
-void ValidateRetainBuffer(void)
-{
-}
-
-void InValidateRetainBuffer(void)
-{
-}
-
-void Retain(unsigned int offset, unsigned int count, void *p)
-{
-}
-
-void Remind(unsigned int offset, unsigned int count, void *p)
-{
-}
-
-void CleanupRetain(void)
-{
-}
-
-void InitRetain(void)
-{
-}
--- a/targets/typemapping.py	Mon Feb 19 19:36:43 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# This file is part of Beremiz, runtime and an Integrated Development Environment for
-# programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
-#
-# Copyright (C) 2011: Edouard TISSERANT and Laurent BESSARD
-#
-# See COPYING.Runtime file for copyrights details.
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-
-from __future__ import absolute_import
-import ctypes
-from ctypes import *
-from datetime import timedelta as td
-
-ctypes.pythonapi.PyString_AsString.argtypes = (ctypes.c_void_p,)
-ctypes.pythonapi.PyString_AsString.restype = ctypes.POINTER(ctypes.c_char)
-
-
-class IEC_STRING(Structure):
-    """
-    Must be changed according to changes in iec_types.h
-    """
-    _fields_ = [("len", c_uint8),
-                ("body", c_char * 126)]
-
-
-class IEC_TIME(Structure):
-    """
-    Must be changed according to changes in iec_types.h
-    """
-    _fields_ = [("s", c_long),   # tv_sec
-                ("ns", c_long)]  # tv_nsec
-
-
-def _t(t, u=lambda x: x.value, p=lambda t, x: t(x)):
-    return (t, u, p)
-
-
-def _ttime():
-    return (IEC_TIME,
-            lambda x: td(0, x.s, x.ns/1000.0),
-            lambda t, x: t(x.days * 24 * 3600 + x.seconds, x.microseconds*1000))
-
-
-SameEndianessTypeTranslator = {
-    "BOOL":       _t(c_uint8, lambda x: x.value != 0),
-    "STEP":       _t(c_uint8),
-    "TRANSITION": _t(c_uint8),
-    "ACTION":     _t(c_uint8),
-    "SINT":       _t(c_int8),
-    "USINT":      _t(c_uint8),
-    "BYTE":       _t(c_uint8),
-    "STRING":     (IEC_STRING,
-                   lambda x: x.body[:x.len],
-                   lambda t, x: t(len(x), x)),
-    "INT":        _t(c_int16),
-    "UINT":       _t(c_uint16),
-    "WORD":       _t(c_uint16),
-    "DINT":       _t(c_int32),
-    "UDINT":      _t(c_uint32),
-    "DWORD":      _t(c_uint32),
-    "LINT":       _t(c_int64),
-    "ULINT":      _t(c_uint64),
-    "LWORD":      _t(c_uint64),
-    "REAL":       _t(c_float),
-    "LREAL":      _t(c_double),
-    "TIME":       _ttime(),
-    "TOD":        _ttime(),
-    "DATE":       _ttime(),
-    "DT":         _ttime(),
-    }
-
-SwapedEndianessTypeTranslator = {
-    # TODO
-    }
-
-TypeTranslator = SameEndianessTypeTranslator
-
-# Construct debugger natively supported types
-DebugTypesSize = dict([(key, sizeof(t)) for key, (t, p, u) in SameEndianessTypeTranslator.iteritems() if t is not None])
-
-
-def UnpackDebugBuffer(buff, indexes):
-    res = []
-    buffoffset = 0
-    buffsize = len(buff)
-    buffptr = cast(ctypes.pythonapi.PyString_AsString(id(buff)), c_void_p).value
-    for iectype in indexes:
-        c_type, unpack_func, _pack_func = \
-            TypeTranslator.get(iectype, (None, None, None))
-        if c_type is not None and buffoffset < buffsize:
-            cursor = c_void_p(buffptr + buffoffset)
-            value = unpack_func(cast(cursor,
-                                     POINTER(c_type)).contents)
-            buffoffset += sizeof(c_type) if iectype != "STRING" else len(value)+1
-            res.append(value)
-        else:
-            break
-    if buffoffset and buffoffset == buffsize:
-        return res
-    return None
-
-
-LogLevels = ["CRITICAL", "WARNING", "INFO", "DEBUG"]
-LogLevelsCount = len(LogLevels)
-LogLevelsDict = dict(zip(LogLevels, range(LogLevelsCount)))
-LogLevelsDefault = LogLevelsDict["DEBUG"]
--- a/tests/tools/test_application.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/tests/tools/test_application.py	Fri Mar 02 17:01:25 2018 +0100
@@ -41,7 +41,7 @@
 
 class UserApplicationTest(unittest.TestCase):
     def InstallExceptionHandler(self):
-        def handle_exception(e_type, e_value, e_traceback):
+        def handle_exception(e_type, e_value, e_traceback, exit=False):
             # traceback.print_exception(e_type, e_value, e_traceback)
             self.exc_info = [e_type, e_value, e_traceback]
         self.exc_info = None
@@ -89,7 +89,9 @@
         # disable default exception handler in Beremiz
         self.app.InstallExceptionHandler = lambda: None
         self.InstallExceptionHandler()
+        self.app.handle_exception = sys.excepthook
         self.app.PreStart()
+        self.ProcessEvents()
         self.app.frame.Show()
         self.ProcessEvents()
         self.app.frame.ShowFullScreen(True)
--- a/tests/wamp/.crossbar/config.json	Mon Feb 19 19:36:43 2018 +0300
+++ b/tests/wamp/.crossbar/config.json	Fri Mar 02 17:01:25 2018 +0100
@@ -1,43 +1,54 @@
-
 {
-   "controller": {
-   },
-   "workers": [
-      {
-         "type": "router",
-         "options": {
-            "pythonpath": [".."]
-         },
-         "realms": [
-            {
-               "name": "Automation",
-               "roles": [
-                  {
-                     "name": "anonymous",
-                     "permissions": [
+    "version": 2,
+    "controller": {},
+    "workers": [
+        {
+            "type": "router",
+            "options": {
+                "pythonpath": [
+                    ".."
+                ]
+            },
+            "realms": [
+                {
+                    "name": "Automation",
+                    "roles": [
                         {
-                           "uri": "*",
-                           "publish": true,
-                           "subscribe": true,
-                           "call": true,
-                           "register": true
+                            "name": "anonymous",
+                            "permissions": [
+                                {
+                                    "uri": "",
+                                    "match": "prefix",
+                                    "allow": {
+                                        "call": true,
+                                        "register": true,
+                                        "publish": true,
+                                        "subscribe": true
+                                    },
+                                    "disclose": {
+                                        "caller": false,
+                                        "publisher": false
+                                    },
+                                    "cache": true
+                                }
+                            ]
                         }
-                     ]
-                  }
-               ]
-            }
-         ],
-         "transports": [
-            {
-               "type": "websocket",
-               "endpoint": {
-                  "type": "tcp",
-                  "port": 8888
-               },
-               "url": "ws://127.0.0.1:8888/",
-               "serializers" : ["msgpack"]
-            }
-         ]
-      }
-   ]
+                    ]
+                }
+            ],
+            "transports": [
+                {
+                    "type": "websocket",
+                    "endpoint": {
+                        "type": "tcp",
+                        "port": 8888
+                    },
+                    "url": "ws://127.0.0.1:8888/",
+                    "serializers": [
+                        "msgpack"
+                    ]
+                }
+            ]
+        }
+    ]
 }
--- a/tests/wamp/README	Mon Feb 19 19:36:43 2018 +0300
+++ b/tests/wamp/README	Fri Mar 02 17:01:25 2018 +0100
@@ -1,12 +1,25 @@
-This project contains wamp client config to be loaded at runtime startup.  
+Crossbar test router configuration is available in .crossbar directory.
+
+Starting command:
+crossbar start
+
+This project contains wamp client config to be loaded at runtime startup.
 
 project_files/wampconf.json
 
 wampconf.json is in "Project Files", so it is copied to runtime's working directory, and then loaded after program transfer + runtime restart.
 
 Otherwise, wamp config file path can be forced :
-./Beremiz_service.py -c  /path/to/my/wampconf.json /working/dir
+./Beremiz_service.py -c /path/to/my/wampconf.json /working/dir
 
-Crossbar test router configuration is available in .crossbar directory. Start with :
-crossbar -d start
+Otherwise, path for CRA secret can be forced :
+./Beremiz_service.py -s /path/to/my/secret /working/dir
 
+Tested on version:
+ Crossbar.io        : 17.12.1 (Crossbar.io COMMUNITY)
+   Autobahn         : 17.10.1 (with JSON, MessagePack, CBOR, UBJSON)
+   Twisted          : 17.9.0-EPollReactor
+   LMDB             : 0.93/lmdb-0.9.18
+   Python           : 2.7.12/CPython
+
+
--- a/tests/wamp/beremiz.xml	Mon Feb 19 19:36:43 2018 +0300
+++ b/tests/wamp/beremiz.xml	Fri Mar 02 17:01:25 2018 +0100
@@ -1,4 +1,4 @@
 <?xml version='1.0' encoding='utf-8'?>
-<BeremizRoot xmlns:xsd="http://www.w3.org/2001/XMLSchema" URI_location="WAMP://127.0.0.1:8888#Automation#2534667845">
+<BeremizRoot xmlns:xsd="http://www.w3.org/2001/XMLSchema" URI_location="WAMP://127.0.0.1:8888#Automation#wamptest">
   <TargetType/>
 </BeremizRoot>
--- a/util/ExceptionHandler.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/util/ExceptionHandler.py	Fri Mar 02 17:01:25 2018 +0100
@@ -37,7 +37,7 @@
 Max_Traceback_List_Size = 20
 
 
-def Display_Exception_Dialog(e_type, e_value, e_tb, bug_report_path):
+def Display_Exception_Dialog(e_type, e_value, e_tb, bug_report_path, exit):
     trcbck_lst = []
     for i, line in enumerate(traceback.extract_tb(e_tb)):
         trcbck = " " + str(i+1) + ". "
@@ -74,6 +74,9 @@
     finally:
         dlg.Destroy()
 
+    if exit:
+        sys.exit()  # wx.Exit()
+
     return res
 
 
@@ -125,7 +128,7 @@
             output.write(a + ":\n" + str(info[a]) + "\n\n")
         output.close()
 
-    def handle_exception(e_type, e_value, e_traceback):
+    def handle_exception(e_type, e_value, e_traceback, exit=False):
         traceback.print_exception(e_type, e_value, e_traceback)  # this is very helpful when there's an exception in the rest of this func
         last_tb = get_last_traceback(e_traceback)
         ex = (last_tb.tb_frame.f_code.co_filename, last_tb.tb_frame.f_lineno)
@@ -135,7 +138,7 @@
             path = tempfile.gettempdir()+os.sep+wx.GetApp().GetAppName()
             bug_report_path = path + os.sep + "bug_report_" + time.strftime("%Y_%m_%d__%H-%M-%S") + ".txt"
             save_bug_report(e_type, e_value, e_traceback, bug_report_path, date)
-            Display_Exception_Dialog(e_type, e_value, e_traceback, bug_report_path)
+            wx.CallAfter(Display_Exception_Dialog, e_type, e_value, e_traceback, bug_report_path, exit)
     # sys.excepthook = lambda *args: wx.CallAfter(handle_exception, *args)
     sys.excepthook = handle_exception
 
@@ -154,3 +157,5 @@
                 sys.excepthook(*sys.exc_info())
         self.run = run_with_except_hook
     threading.Thread.__init__ = init
+
+    return handle_exception
--- a/util/ProcessLogger.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/util/ProcessLogger.py	Fri Mar 02 17:01:25 2018 +0100
@@ -29,9 +29,7 @@
 import subprocess
 import ctypes
 from threading import Timer, Lock, Thread, Semaphore
-import wx
-if os.name == 'posix':
-    from signal import SIGTERM, SIGKILL
+import signal
 
 
 class outputThread(Thread):
@@ -126,11 +124,11 @@
             "stderr": subprocess.PIPE
         }
 
-        if no_gui and wx.Platform == '__WXMSW__':
+        if no_gui and os.name in ("nt", "ce"):
             self.startupinfo = subprocess.STARTUPINFO()
             self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
             popenargs["startupinfo"] = self.startupinfo
-        elif wx.Platform == '__WXGTK__':
+        elif os.name == 'posix':
             popenargs["shell"] = False
 
         if timeout:
@@ -200,16 +198,16 @@
 
         self.outt.killed = True
         self.errt.killed = True
-        if wx.Platform == '__WXMSW__':
+        if os.name in ("nt", "ce"):
             PROCESS_TERMINATE = 1
             handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, self.Proc.pid)
             ctypes.windll.kernel32.TerminateProcess(handle, -1)
             ctypes.windll.kernel32.CloseHandle(handle)
         else:
             if gently:
-                sig = SIGTERM
+                sig = signal.SIGTERM
             else:
-                sig = SIGKILL
+                sig = signal.SIGKILL
             try:
                 os.kill(self.Proc.pid, sig)
             except Exception:
--- a/util/misc.py	Mon Feb 19 19:36:43 2018 +0300
+++ b/util/misc.py	Fri Mar 02 17:01:25 2018 +0100
@@ -47,14 +47,21 @@
     return True
 
 
-def GetClassImporter(classpath):
-    if isinstance(classpath, str):
-        def fac():
-            mod = __import__(classpath.rsplit('.', 1)[0])
-            return reduce(getattr, classpath.split('.')[1:], mod)
-        return fac
+def GetClassImporter(param):
+    """
+    is used to resolve library class names in features.py
+    if param is a string, returns a callable that return the class pointed by param
+    if a class is given, then returns a callable that returns the given class.
+    """
+
+    if isinstance(param, str):
+        def factory():
+            # on-demand import, only when using class
+            mod = __import__(param.rsplit('.', 1)[0])
+            return reduce(getattr, param.split('.')[1:], mod)
+        return factory
     else:
-        return classpath
+        return lambda: param
 
 
 def InstallLocalRessources(CWD):