--- 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] | 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]">
- <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] | 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]">
- <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] | 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]">
- <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] | 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]">
- <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] | 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]"/>
- </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] | 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]"/>
- </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] | 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]">
- <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] | 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]"/>
- </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):