lpcmanager

7a1ab1acd727
Merged revamp branch until cross_toolchain related changes
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore Wed Apr 11 13:06:58 2018 +0200
@@ -0,0 +1,5 @@
+.project
+
+syntax: regexp
+^.*\.pyc$
+^.*\.swp$
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LPCArch.py Wed Apr 11 13:06:58 2018 +0200
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+
+# XXX Where is MC8 ?
+PLC_GOT_module = ['GOT', 'GOT_111', 'GOT_131']
+PLC_MC9_module = ['MC9']
+PLC_module = PLC_MC9_module + PLC_GOT_module
+
+arch = None
+
+def SetLPCArch(given):
+ global arch
+ arch = given
+
+def GetLPCArch():
+ return arch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LPCBeremiz.py Wed Apr 11 13:06:58 2018 +0200
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+import wx
+from BeremizIDE import *
+from VariableExporter import VariableWriter
+
+# XXX TODO : strip dead code. document.
+
+lpcberemiz_cmd = None
+
+
+SCROLLBAR_UNIT = 10
+ID_EXPORT = 7500
+
+
+class LPCBeremiz(Beremiz):
+ def _init_coll_FileMenu_Items(self, parent):
+ config = wx.ConfigBase.Get()
+ export = str(config.Read("Exporter"))
+ if export == "":
+ config.Write("Exporter", '0')
+ export = '0'
+ if export == '1':
+ export = True
+ else:
+ export = False
+ AppendMenu(parent, help='', id=wx.ID_SAVE,
+ kind=wx.ITEM_NORMAL, text=_(u'Save\tCTRL+S'))
+ AppendMenu(parent, help='', id=wx.ID_CLOSE,
+ kind=wx.ITEM_NORMAL, text=_(u'Close Tab\tCTRL+W'))
+ parent.AppendSeparator()
+ AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP,
+ kind=wx.ITEM_NORMAL, text=_(u'Page Setup'))
+ AppendMenu(parent, help='', id=wx.ID_PREVIEW,
+ kind=wx.ITEM_NORMAL, text=_(u'Preview'))
+ AppendMenu(parent, help='', id=wx.ID_PRINT,
+ kind=wx.ITEM_NORMAL, text=_(u'Print'))
+ parent.AppendSeparator()
+ if export:
+ AppendMenu(parent, help='', id=ID_EXPORT,
+ kind=wx.ITEM_NORMAL, text=_(u'Export'))
+ parent.AppendSeparator()
+ AppendMenu(parent, help='', id=wx.ID_EXIT,
+ kind=wx.ITEM_NORMAL, text=_(u'Quit\tCTRL+Q'))
+
+ self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE)
+ self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE)
+ self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP)
+ self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW)
+ self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT)
+ if export:
+ self.Bind(wx.EVT_MENU, lambda event: VariableWriter(self, event, self.CTR.ProjectPath), id=ID_EXPORT)
+ self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT)
+
+ self.AddToMenuToolBar([(wx.ID_SAVE, "save", _(u'Save'), None),
+ (wx.ID_PRINT, "print", _(u'Print'), None)])
+
+
+
+ def _init_ctrls(self, prnt):
+ Beremiz._init_ctrls(self, prnt)
+
+ def __init__(self, *args, **kwargs):
+ """
+ LPCBeremiz needs to keep track of connection to composer
+ in order to later signal when frame is closed
+ """
+ self.lpcberemiz_cmd_pipe = kwargs.pop("pipe")
+ Beremiz.__init__(self, *args, **kwargs)
+
+ def Show(self, loading=True):
+ wx.Frame.Show(self)
+
+ def OnCloseFrame(self, event):
+ """
+ Intercepts Close Frame event and veto it
+ Frame doesn't really close, but just hide.
+ Message is sent to Composer to signal app being closed.
+ """
+ if self.CheckSaveBeforeClosing(_("Close Application")):
+
+ wx.Frame.Hide(self)
+
+ self.CTR.ResetAppFrame(self.lpcberemiz_cmd_pipe)
+
+ self.CTR.KillDebugThread()
+ self.KillLocalRuntime()
+
+ self.SaveLastState()
+
+ self.lpcberemiz_cmd_pipe.write("Closed\n")
+
+ event.Veto()
+
+ def RefreshTitle(self):
+ name = _("Beremiz")
+ if self.CTR is not None:
+ projectname = self.CTR.GetProjectName()
+ if self.CTR.ProjectTestModified():
+ projectname = "~%s~" % projectname
+ self.SetTitle("%s - %s" % (name, projectname))
+ else:
+ self.SetTitle(name)
+
+ def RefreshFileMenu(self):
+ MenuToolBar = self.Panes["MenuToolBar"]
+ if self.CTR is not None:
+ selected = self.TabsOpened.GetSelection()
+ if selected >= 0:
+ graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer)
+ else:
+ graphic_viewer = False
+ if self.TabsOpened.GetPageCount() > 0:
+ self.FileMenu.Enable(wx.ID_CLOSE, True)
+ if graphic_viewer:
+ self.FileMenu.Enable(wx.ID_PREVIEW, True)
+ self.FileMenu.Enable(wx.ID_PRINT, True)
+ MenuToolBar.EnableTool(wx.ID_PRINT, True)
+ else:
+ self.FileMenu.Enable(wx.ID_PREVIEW, False)
+ self.FileMenu.Enable(wx.ID_PRINT, False)
+ MenuToolBar.EnableTool(wx.ID_PRINT, False)
+ else:
+ self.FileMenu.Enable(wx.ID_CLOSE, False)
+ self.FileMenu.Enable(wx.ID_PREVIEW, False)
+ self.FileMenu.Enable(wx.ID_PRINT, False)
+ MenuToolBar.EnableTool(wx.ID_PRINT, False)
+ self.FileMenu.Enable(wx.ID_PAGE_SETUP, True)
+ project_modified = self.CTR.ProjectTestModified()
+ self.FileMenu.Enable(wx.ID_SAVE, project_modified)
+ MenuToolBar.EnableTool(wx.ID_SAVE, project_modified)
+ else:
+ self.FileMenu.Enable(wx.ID_CLOSE, False)
+ self.FileMenu.Enable(wx.ID_PAGE_SETUP, False)
+ self.FileMenu.Enable(wx.ID_PREVIEW, False)
+ self.FileMenu.Enable(wx.ID_PRINT, False)
+ MenuToolBar.EnableTool(wx.ID_PRINT, False)
+ self.FileMenu.Enable(wx.ID_SAVE, False)
+ MenuToolBar.EnableTool(wx.ID_SAVE, False)
+
+ def RefreshScrollBars(self):
+ xstart, ystart = self.PLCConfig.GetViewStart()
+ window_size = self.PLCConfig.GetClientSize()
+ sizer = self.PLCConfig.GetSizer()
+ if sizer:
+ maxx, maxy = sizer.GetMinSize()
+ posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
+ posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
+ self.PLCConfig.Scroll(posx, posy)
+ self.PLCConfig.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
+ maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
+
+ def RefreshAll(self):
+ Beremiz.RefreshAll(self)
+
+ # Remove taskbar icon when simulating
+ def StartLocalRuntime(self, taskbaricon=True):
+ return Beremiz.StartLocalRuntime(self, taskbaricon=False)
+
--- a/LPCBus.py Tue Jan 30 14:25:10 2018 +0100
+++ b/LPCBus.py Wed Apr 11 13:06:58 2018 +0200
@@ -1,7 +1,16 @@
+from __future__ import absolute_import
import os
modpath = os.path.split(__file__)[0]
+from LPCArch import GetLPCArch, PLC_module
+arch = GetLPCArch()
+if arch in PLC_module:
+ bus_template_name = "MC9"
+else:
+ bus_template_name = arch
+
+
def GetLocalCode(fname):
return open(os.path.join(modpath,"LPCBus",fname)).read()
@@ -17,10 +26,6 @@
LPCBusLDFLAGS = { "MC9:On Board" : "-lmbrtu" }
-# to be overloaded at import
-LPCarch = None
-arch = None
-
import os
from plcopen.structures import LOCATIONDATATYPES
from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP,\
@@ -281,7 +286,7 @@
if var["Publish"] != "":
code_str["publish_code"] += " " + var["Publish"] % ("*" + var["location"]) + "\n"
- BusName = LPCarch + ":" + self.BaseParams.getName()
+ BusName = bus_template_name + ":" + self.BaseParams.getName()
def bcode(section):
@@ -299,12 +304,12 @@
"bus_publish_code": bcode("publish"),
})
- if LPCarch not in bus_template_code:
+ if bus_template_name not in bus_template_code:
raise Exception, "Unknown arch %s. Please use %s"%(
- LPCarch,repr(bus_template_code.keys()))
+ bus_template_name,repr(bus_template_code.keys()))
Gen_Module_path = os.path.join(buildpath, "Bus_%s.c"%location_str)
module = open(Gen_Module_path,'w')
- module.write(bus_template_code[LPCarch] % code_str)
+ module.write(bus_template_code[bus_template_name] % code_str)
module.close()
matiec_flags = '"-I%s" -Wno-unused-function'%os.path.abspath(self.GetCTRoot().GetIECLibPath())
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LPCCanFestival.py Wed Apr 11 13:06:58 2018 +0200
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+import os
+
+from ConfigTreeNode import ConfigTreeNode
+
+from canfestival import RootClass as CanOpenRootClass
+from canfestival.canfestival import _SlaveCTN, _NodeListCTN, NodeManager
+from canfestival.NetworkEditor import NetworkEditor
+from canfestival.SlaveEditor import SlaveEditor
+
+from canfestival import canfestival
+defaultGetCFLAGS = canfestival.local_canfestival_config.getCFLAGS
+defaultGetLDFLAGS = canfestival.local_canfestival_config.getLDFLAGS
+
+def getCFLAGS(*args):
+ return str(defaultGetCFLAGS(*args))
+
+def getLDFLAGS(*args):
+ return str(defaultGetLDFLAGS(*args))
+
+canfestival.local_canfestival_config.getCFLAGS = getCFLAGS
+canfestival.local_canfestival_config.getLDFLAGS = getLDFLAGS
+
+DEFAULT_SETTINGS = {
+ "CAN_Baudrate": "125K",
+ "Slave_NodeId": 2,
+ "Master_NodeId": 1,
+}
+
+class LPCSlaveEditor(SlaveEditor):
+ # SHOW_BASE_PARAMS = False
+ pass
+
+
+class LPCCanOpenSlave(_SlaveCTN):
+ XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="CanFestivalSlaveNode">
+ <xsd:complexType>
+ <xsd:attribute name="CAN_Baudrate" type="xsd:string" use="optional" default="%(CAN_Baudrate)s"/>
+ <xsd:attribute name="NodeId" type="xsd:integer" use="optional" default="%(Slave_NodeId)d"/>
+ <xsd:attribute name="Sync_Align" type="xsd:integer" use="optional" default="0"/>
+ <xsd:attribute name="Sync_Align_Ratio" use="optional" default="50">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:integer">
+ <xsd:minInclusive value="1"/>
+ <xsd:maxInclusive value="99"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ """ % DEFAULT_SETTINGS
+
+ EditorType = LPCSlaveEditor
+
+ def __init__(self):
+ # TODO change netname when name change
+ NodeManager.__init__(self)
+ odfilepath = self.GetSlaveODPath()
+ if (os.path.isfile(odfilepath)):
+ self.OpenFileInCurrent(odfilepath)
+ else:
+ self.CreateNewNode("SlaveNode", # Name - will be changed at build time
+ 0x00, # NodeID - will be changed at build time
+ "slave", # Type
+ "", # description
+ "None", # profile
+ "", # prfile filepath
+ "heartbeat", # NMT
+ []) # options
+ self.OnCTNSave()
+
+ def GetCanDevice(self):
+ return str(self.BaseParams.getIEC_Channel())
+
+ ConfNodeMethods = [
+ {"bitmap": "NetworkEdit",
+ "name": _("Edit slave"),
+ "tooltip": _("Edit CanOpen slave with ObjdictEdit"),
+ "method": "_OpenView"},
+ ] + _SlaveCTN.ConfNodeMethods
+
+
+class LPCNetworkEditor(NetworkEditor):
+ # SHOW_BASE_PARAMS = False
+ pass
+
+
+class LPCCanOpenMaster(_NodeListCTN):
+ XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="CanFestivalNode">
+ <xsd:complexType>
+ <xsd:attribute name="CAN_Baudrate" type="xsd:string" use="optional" default="%(CAN_Baudrate)s"/>
+ <xsd:attribute name="NodeId" type="xsd:integer" use="optional" default="%(Master_NodeId)d"/>
+ <xsd:attribute name="Sync_TPDOs" type="xsd:boolean" use="optional" default="true"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ """ % DEFAULT_SETTINGS
+
+ EditorType = LPCNetworkEditor
+
+ def GetCanDevice(self):
+ return str(self.BaseParams.getIEC_Channel())
+
+ ConfNodeMethods = [
+ {"bitmap": "NetworkEdit",
+ "name": _("Edit network"),
+ "tooltip": _("Edit CanOpen Network with NetworkEdit"),
+ "method": "_OpenView"},
+ ] + _NodeListCTN.ConfNodeMethods
+
+
+class LPCCanOpen(CanOpenRootClass):
+ XSD = None
+ CTNChildrenTypes = [("CanOpenNode", LPCCanOpenMaster, "CanOpen Master"),
+ ("CanOpenSlave", LPCCanOpenSlave, "CanOpen Slave")]
+
+ def GetCanDriver(self):
+ return None
+
+ def LoadChildren(self):
+ ConfigTreeNode.LoadChildren(self)
+
+ if self.GetChildByName("Master") is None:
+ master = self.CTNAddChild("Master", "CanOpenNode", 0)
+ # master.BaseParams.setEnabled(False)
+ master.CTNRequestSave()
+
+ if self.GetChildByName("Slave") is None:
+ slave = self.CTNAddChild("Slave", "CanOpenSlave", 1)
+ # slave.BaseParams.setEnabled(False)
+ slave.CTNRequestSave()
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LPCCommand.py Wed Apr 11 13:06:58 2018 +0200
@@ -0,0 +1,359 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+import sys
+import cmd
+from threading import Thread, Semaphore, Lock, Timer
+from types import StringType, UnicodeType
+import wx
+
+from LPCBus import *
+from PLCControler import LOCATION_MODULE, LOCATION_GROUP
+
+build_lock = Lock()
+wx_eval_lock = Semaphore(0)
+eval_res = None
+
+# Command log for debug, for viewing from wxInspector
+# __builtins__.cmdlog = []
+
+def wx_evaluator(callable, *args, **kwargs):
+ global eval_res
+ eval_res = None
+ try:
+ eval_res = callable(*args, **kwargs)
+ finally:
+ wx_eval_lock.release()
+
+
+def evaluator(callable, *args, **kwargs):
+ global eval_res
+ wx.CallAfter(wx_evaluator, callable, *args, **kwargs)
+ wx_eval_lock.acquire()
+ return eval_res
+
+
+def location(loc):
+ return tuple(map(int, loc.split(".")))
+
+class LPCCommand(cmd.Cmd):
+
+ prompt = ""
+ RefreshTimer = None
+
+ def __init__(self, Launcher, CTR, Log):
+ cmd.Cmd.__init__(self, stdin=Log, stdout=Log)
+ self.use_rawinput = False
+ self.restore_last_state = False
+ self.Launcher = Launcher
+ self.Log = Log
+ self.CTR = CTR
+ for function, (arg_types, opt) in [
+ ("Exit", ([], 0)),
+ ("Show", ([bool], 1)),
+ ("Refresh", ([], 0)),
+ ("Close", ([], 0)),
+ ("Compile", ([], 0)),
+ ("SetProjectProperties", ([str, str, str, str], 0)),
+ ("SetOnlineMode", ([str, str], 1)),
+ ("AddBus", ([int, str, str], 1)),
+ ("RenameBus", ([int, str], 0)),
+ ("ChangeBusIECChannel", ([int, int], 0)),
+ ("RemoveBus", ([int], 0)),
+ ("AddModule", ([location, int, str, str, str], 1)),
+ ("RenameModule", ([location, str], 0)),
+ ("ChangeModuleIECChannel", ([location, int], 0)),
+ ("ChangeModuleInitCode", ([location, str], 0)),
+ ("RemoveModule", ([location, int], 0)),
+ ("StartGroup", ([location, str, str], 1)),
+ ("AddVariable", ([location, location, str, str, str, str, str, str], 1)),
+ ("ChangeVariableParams", ([location, location, str, str, str, str, str, str], 1)),
+ ("RemoveVariable", ([location, location], 0))
+ ]:
+ self.SetCmdFunc(function, arg_types, opt)
+
+ def SetCmdFunc(self, function, arg_types, opt):
+ setattr(self, "do_%s" % function,
+ lambda line : self.CmdFunction(
+ line, function, arg_types, opt))
+
+ def CmdFunction(self, line, function, arg_types, opt):
+ arg_number = len(arg_types)
+ args_toks = line.split('"')
+ if len(args_toks) % 2 == 0:
+ self.Log.write("Error: Invalid command\n")
+ sys.stdout.flush()
+ return
+ args = []
+ for num, arg in enumerate(args_toks):
+ if num % 2 == 0:
+ stripped = arg.strip()
+ if stripped:
+ args.extend(stripped.split(" "))
+ else:
+ args.append(arg)
+ number = None
+ extra = ""
+ if opt == 0 and len(args) != arg_number:
+ number = arg_number
+ elif len(args) > arg_number:
+ number = arg_number
+ extra = " at most"
+ elif len(args) < arg_number - opt:
+ number = arg_number - opt
+ extra = " at least"
+ if number is not None:
+ if number == 0:
+ self.Log.write("Error: No argument%s expected for %s\n" % (extra, function))
+ elif number == 1:
+ self.Log.write("Error: 1 argument%s expected for %s\n" % (extra, function))
+ else:
+ self.Log.write("Error: %d arguments%s expecte for %s\n" % (number, extra, function))
+ sys.stdout.flush()
+ return
+ for num, arg in enumerate(args):
+ try:
+ args[num] = arg_types[num](arg)
+ except:
+ self.Log.write("Error: Invalid value for argument %d\n" % (num + 1))
+ sys.stdout.flush()
+ return
+
+ func = getattr(self, function)
+ res = evaluator(func, *args)
+
+ # cmdlog.append((function, line, res))
+ # if len(cmdlog) > 100: # prevent debug log to grow too much
+ # cmdlog.pop(0)
+
+ if isinstance(res, (StringType, UnicodeType)):
+ self.Log.write(res)
+ return False
+ else:
+ return res
+
+ def RestartTimer(self):
+ if self.RefreshTimer is not None:
+ self.RefreshTimer.cancel()
+ self.RefreshTimer = Timer(0.1, wx.CallAfter, args=[self.Refresh])
+ self.RefreshTimer.start()
+
+ def Exit(self):
+ self.Close()
+ self.Launcher.app.ExitMainLoop()
+ return True
+
+ def do_EOF(self, line):
+ return self.Exit()
+
+ def Show(self, loading=False):
+ """
+ Doesn't do anything on MC9
+ Was usefull at some time on MC8...
+ """
+ pass
+
+ def Refresh(self):
+ if self.Launcher.frame is not None:
+ if self.restore_last_state:
+ self.restore_last_state = False
+ self.Launcher.frame.RestoreLastState()
+ else:
+ self.Launcher.frame.RefreshEditor()
+ self.Launcher.frame.RefreshAfterLoad()
+ self.Launcher.frame.RefreshAll()
+
+ def Close(self):
+ self.CTR.ResetAppFrame(self.Log)
+ if self.Launcher.frame is not None:
+ self.Launcher.frame.Hide()
+
+ def Compile(self):
+ self.CTR._Build()
+
+ def SetProjectProperties(self, projectname, productname, productversion, companyname):
+ new_properties = {
+ "projectName": projectname,
+ "productName": productname,
+ "productVersion": productversion,
+ "companyName": companyname}
+ self.CTR.SetProjectProperties(properties=new_properties, buffer=False)
+ self.RestartTimer()
+
+ def SetOnlineMode(self, mode, path=None):
+ self.CTR.SetOnlineMode(mode, path)
+ self.RestartTimer()
+
+ def AddBus(self, iec_channel, name, icon=None):
+ for child in self.CTR.IterChildren():
+ if child.BaseParams.getName() == name:
+ return "Error: A bus named %s already exists\n" % name
+ elif child.BaseParams.getIEC_Channel() == iec_channel:
+ return "Error: A bus with IEC_channel %d already exists\n" % iec_channel
+ bus = self.CTR.CTNAddChild(name, "LPCBus", iec_channel)
+ if bus is None:
+ return "Error: Unable to create bus\n"
+ bus.SetIcon(icon)
+ self.RestartTimer()
+
+ def RenameBus(self, iec_channel, name):
+ bus = self.CTR.GetChildByIECLocation((iec_channel,))
+ if bus is None:
+ return "Error: No bus found\n"
+ for child in self.CTR.IterChildren():
+ if child != bus and child.BaseParams.getName() == name:
+ return "Error: A bus named %s already exists\n" % name
+ bus.BaseParams.setName(name)
+ self.RestartTimer()
+
+ def ChangeBusIECChannel(self, old_iec_channel, new_iec_channel):
+ bus = self.CTR.GetChildByIECLocation((old_iec_channel,))
+ if bus is None:
+ return "Error: No bus found\n"
+ for child in self.CTR.IterChildren():
+ if child != bus and child.BaseParams.getIEC_Channel() == new_iec_channel:
+ return "Error: A bus with IEC_channel %d already exists\n" % new_iec_channel
+ self.CTR.UpdateProjectVariableLocation(str(old_iec_channel),
+ str(new_iec_channel))
+ bus.BaseParams.setIEC_Channel(new_iec_channel)
+ self.RestartTimer()
+
+ def RemoveBus(self, iec_channel):
+ bus = self.CTR.GetChildByIECLocation((iec_channel,))
+ if bus is None:
+ return "Error: No bus found\n"
+ self.CTR.RemoveProjectVariableByFilter(str(iec_channel))
+ self.CTR.Children["LPCBus"].remove(bus)
+ self.RestartTimer()
+
+ def AddModule(self, parent, iec_channel, name, icode, icon=None):
+ module = self.CTR.GetChildByIECLocation(parent)
+ if module is None:
+ return "Error: No parent found\n"
+ for child in GetModuleChildren(module):
+ if child["name"] == name:
+ return "Error: A module named %s already exists\n" % name
+ elif child["IEC_Channel"] == iec_channel:
+ return "Error: A module with IEC_channel %d already exists\n" % iec_channel
+ GetLastModuleGroup(module).append({"name": name,
+ "type": LOCATION_MODULE,
+ "IEC_Channel": iec_channel,
+ "icon": icon,
+ "init": icode,
+ "children": []})
+ self.RestartTimer()
+
+ def RenameModule(self, iec_location, name):
+ module = self.CTR.GetChildByIECLocation(iec_location)
+ if module is None:
+ return "Error: No module found\n"
+ parent = self.CTR.GetChildByIECLocation(iec_location[:-1])
+ if parent is self.CTR:
+ return "Error: No module found\n"
+ if module["name"] != name:
+ for child in GetModuleChildren(parent):
+ if child["name"] == name:
+ return "Error: A module named %s already exists\n" % name
+ module["name"] = name
+ self.RestartTimer()
+
+ def ChangeModuleIECChannel(self, old_iec_location, new_iec_channel):
+ module = self.CTR.GetChildByIECLocation(old_iec_location)
+ if module is None:
+ return "Error: No module found\n"
+ parent = self.CTR.GetChildByIECLocation(old_iec_location[:-1])
+ if parent is self.CTR:
+ return "Error: No module found\n"
+ if module["IEC_Channel"] != new_iec_channel:
+ for child in GetModuleChildren(parent):
+ if child["IEC_Channel"] == new_iec_channel:
+ return "Error: A module with IEC_channel %d already exists\n" % new_iec_channel
+ self.CTR.UpdateProjectVariableLocation(".".join(map(str, old_iec_location)),
+ ".".join(map(str, old_iec_location[:1] + (new_iec_channel,))))
+ module["IEC_Channel"] = new_iec_channel
+ self.RestartTimer()
+
+ def ChangeModuleInitCode(self, iec_location, icode):
+ module = self.CTR.GetChildByIECLocation(iec_location)
+ if module is None:
+ return "Error: No module found\n"
+ module["init"] = icode
+
+ def RemoveModule(self, parent, iec_channel):
+ module = self.CTR.GetChildByIECLocation(parent)
+ if module is None:
+ return "Error: No parent found\n"
+ child = GetModuleBySomething(module, "IEC_Channel", (iec_channel,))
+ if child is None:
+ return "Error: No module found\n"
+ self.CTR.RemoveProjectVariableByFilter(".".join(map(str, parent + (iec_channel,))))
+ RemoveModuleChild(module, child)
+ self.RestartTimer()
+
+ def StartGroup(self, parent, name, icon=None):
+ module = self.CTR.GetChildByIECLocation(parent)
+ if module is None:
+ return "Error: No parent found\n"
+ for child in module["children"]:
+ if child["type"] == LOCATION_GROUP and child["name"] == name:
+ return "Error: A group named %s already exists\n" % name
+ module["children"].append({"name": name,
+ "type": LOCATION_GROUP,
+ "icon": icon,
+ "children": []})
+ self.RestartTimer()
+
+ def AddVariable(self, parent, location, name, direction, type, rcode, pcode, description=""):
+ module = self.CTR.GetChildByIECLocation(parent)
+ if module is None:
+ return "Error: No parent found\n"
+ for child in GetModuleChildren(module):
+ if child["name"] == name:
+ return "Error: A variable named %s already exists\n" % name
+ if child["location"] == location and child["type"] == LOCATION_TYPES[direction]:
+ return "Error: A variable with location %s already exists\n" % ".".join(map(str, location))
+ GetLastModuleGroup(module).append({"name": name,
+ "location": location,
+ "type": LOCATION_TYPES[direction],
+ "IEC_type": type,
+ "description": description,
+ "retrieve": rcode,
+ "publish": pcode})
+ self.RestartTimer()
+
+ def ChangeVariableParams(self, parent, location, new_name, new_direction, new_type, new_rcode, new_pcode,
+ new_description=None):
+ module = self.CTR.GetChildByIECLocation(parent)
+ if module is None:
+ return "Error: No parent found\n"
+ variable = None
+ for child in GetModuleChildren(module):
+ if child["location"] == location and child["type"] == LOCATION_TYPES[new_direction]:
+ variable = child
+ elif child["name"] == new_name:
+ return "Error: A variable named %s already exists\n" % new_name
+ if variable is None:
+ return "Error: No variable found\n"
+ if variable["name"] != new_name:
+ self.CTR.UpdateProjectVariableName(variable["name"], new_name)
+ variable["name"] = new_name
+ variable["type"] = LOCATION_TYPES[new_direction]
+ variable["IEC_type"] = new_type
+ variable["retrieve"] = new_rcode
+ variable["publish"] = new_pcode
+ if new_description is not None:
+ variable["description"] = new_description
+ self.RestartTimer()
+
+ def RemoveVariable(self, parent, location, direction):
+ module = self.CTR.GetChildByIECLocation(parent)
+ if module is None:
+ return "Error: No parent found\n"
+ child = GetModuleVariable(module, location, direction)
+ if child is None:
+ return "Error: No variable found\n"
+ size = LOCATION_SIZES[self.CTR.GetBaseType(child["IEC_type"])]
+ address = "%" + LOCATION_DIRS[child["type"]] + size + ".".join(map(str, parent + location))
+ self.CTR.RemoveProjectVariableByAddress(address)
+ RemoveModuleChild(module, child)
+ self.RestartTimer()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LPCExtension.py Wed Apr 11 13:06:58 2018 +0200
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+#
+# --------- Libraries Extension ------------
+#
+
+import features
+from POULibrary import SimplePOULibraryFactory
+from LPCArch import arch, PLC_MC9_module, PLC_GOT_module
+
+# _lpcmanager_path, arch, etc are defined here because
+# globals() of LPCManager.py are passed to extentions
+
+features.libraries=[('Native', 'NativeLib.NativeLibrary')]
+
+def _poulibpath(name):
+ return os.path.join(_lpcmanager_path, 'Pous', "pous"+name+".xml")
+
+if arch in PLC_MC9_module:
+ features.libraries += [('Python', 'py_ext.PythonLibrary'),
+ ('RTC', SimplePOULibraryFactory(_poulibpath("RTC")))]
+elif arch in PLC_GOT_module:
+ features.libraries += [('Python', 'py_ext.PythonLibrary'),
+ ('RTC', SimplePOULibraryFactory(_poulibpath("RTC"))),
+ ('GOT', SimplePOULibraryFactory(_poulibpath("GOT")))]
+else:
+ features.libraries += [('LPC', SimplePOULibraryFactory(_poulibpath("LPC")))]
+
+#
+# --------- Configuration Tree Nodes (CTN) catalog extension ------------
+#
+_oldcatalog = features.catalog
+catalog_index = dict(zip(zip(*_oldcatalog)[0],_oldcatalog))
+wanted_beremiz_features = [catalog_index[feature]
+ for feature in ["modbus", "c_ext", "py_ext"]]
+features.catalog = wanted_beremiz_features + [
+ ('LPCBus', _('LPC bus'), _('Support for Smarteh modules'), 'LPCBus.LPCBus'),
+ ('CanOpen', _('CANOpen'), _('Support for CANopen'), 'LPCCanFestival.LPCCanOpen')]
+
+#
+# --------- Connectors Extension ------------
+#
+
+import connectors
+from LPCconnector import LPC_connector_factory
+
+connectors.connectors["LPC"] = lambda: LPC_connector_factory
+
+#
+# --------- Targets/Toolchains Extension ------------
+#
+
+import targets
+from LPCtarget import LPC_target
+
+targets.targets["LPC"] = {"xsd": os.path.join(_lpcmanager_path, "LPCtarget", "XSD"),
+ "class": lambda: LPC_target,
+ "code": {os.path.join(_lpcmanager_path, "LPCtarget", "plc_LPC_main.c")}}
+targets.toolchains["makefile"] = os.path.join(_lpcmanager_path, "LPCtarget", "XSD_toolchain_makefile")
+targets.targets["MC9"] = {"xsd": os.path.join(_lpcmanager_path, "MC9target", "XSD"),
+ "class": targets.targets["Xenomai"]["class"],
+ "code": {"plc_MC9_main.c": targets.targets["Xenomai"]["code"]["plc_Xenomai_main.c"],
+ "plc_MC9_main_retain.c": os.path.join(_lpcmanager_path,
+ "MC9target", "plc_MC9_main_retain.c")}}
--- a/LPCManager.py Tue Jan 30 14:25:10 2018 +0100
+++ b/LPCManager.py Wed Apr 11 13:06:58 2018 +0200
@@ -1,7 +1,12 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
+from __future__ import absolute_import
import sys
import os
+import getopt
+import __builtin__
+import time
+from threading import Thread
# On Windows install schema, we compute path to beremiz
# relative to path to python folder (sys.path[0] in that case)
@@ -11,2553 +16,96 @@
# Then we add it to sys.path, to make "import Beremiz" possible
sys.path.append(_beremiz_folder)
-import fnmatch
-import shutil
-import socket
-import threading
-import zipfile
-import tempfile
-import getopt
-import __builtin__
-from types import StringType, UnicodeType
-import time
import wx
+from util.BitmapLibrary import AddBitmapFolder
# Path of directory containing current python file
_lpcmanager_path = os.path.split(__file__)[0]
-# XXX Where is MC8 ?
-PLC_GOT_module = ['GOT', 'GOT_111', 'GOT_131']
-PLC_MC9_module = ['MC9']
-PLC_module = PLC_MC9_module + PLC_GOT_module
-arch = None
-
-def usage():
- print "\nUsage of LPCManager.py :"
- print "\n %s Projectpath Buildpath port arch\n" % sys.argv[0]
-
-# Command line arguments parsing
-try:
- opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
-except getopt.GetoptError:
- # print help information and exit:
- usage()
- sys.exit(2)
-
-# asking for help causes exit
-for o, a in opts:
- if o in ("-h", "--help"):
- usage()
- sys.exit()
-
-if len(args) != 4 :
- usage()
- sys.exit()
-else:
- projectOpen = args[0]
- buildpath = args[1]
- try:
- port = int(args[2])
- except:
- usage()
- sys.exit()
- arch = args[3]
-
-# BEREMIZ_DEBUG file detection in beremiz isn't enough (module scope)
-# here we set BMZ_DBG interpreter-wise, so that submodules can use it.
-__builtin__.__dict__["BMZ_DBG"] = os.path.exists("LPC_DEBUG")
-
-if wx.VERSION >= (3, 0, 0):
- app = wx.App(redirect=BMZ_DBG)
-else:
- app = wx.PySimpleApp(redirect=BMZ_DBG)
-app.SetAppName('beremiz')
-if wx.VERSION < (3, 0, 0):
- wx.InitAllImageHandlers()
-
-from util.misc import InstallLocalRessources
-
-InstallLocalRessources(_beremiz_folder)
-
-from util.BitmapLibrary import AddBitmapFolder
-AddBitmapFolder(os.path.join(_lpcmanager_path, "images"))
-
-
-_lpcmanager_path = os.path.split(__file__)[0]
-import features
-from POULibrary import POULibrary
-
-class PLCLibraryLPC(POULibrary):
- def GetLibraryPath(self):
- return os.path.join(_lpcmanager_path + '/Pous/', "pousLPC.xml")
-
-class PLCLibraryGOT(POULibrary):
- def GetLibraryPath(self):
- return os.path.join(_lpcmanager_path + '/Pous/', "pousGOT.xml")
-
-class PLCLibraryRTC(POULibrary):
- def GetLibraryPath(self):
- return os.path.join(_lpcmanager_path + '/Pous/', "pousRTC.xml")
-
-features.libraries=[('Native', 'NativeLib.NativeLibrary')]
-
-if arch in PLC_MC9_module:
- features.libraries += [('Python', 'py_ext.PythonLibrary'), ('RTC', lambda: PLCLibraryRTC)]
-elif arch in PLC_GOT_module:
- features.libraries += [('Python', 'py_ext.PythonLibrary'), ('RTC', lambda: PLCLibraryRTC), ('GOT', lambda: PLCLibraryGOT)]
-else:
- features.libraries += [('LPC', lambda: PLCLibraryLPC)]
-
-features.catalog.pop([i for i, x in enumerate(features.catalog) if x[0].startswith('svg')][0])
-
-wxglade_hmi_index = [i for i, x in enumerate(features.catalog) if x[0].startswith('wxglade_hmi')][0]
-old_wxglade_hmi = features.catalog[wxglade_hmi_index]
-mwwxglade_hmi = ('wxglade_hmi', _('WxGlade GUI'), _('Add a simple WxGlade based GUI.'), 'MWWxglade_hmi.mwwxglade_hmi.WxGladeHMI')
-features.catalog[wxglade_hmi_index] = mwwxglade_hmi
-
-modbus_features = ('modbus', _('Modbus support'), _('Map located variables over Modbus'), 'modbus.modbus.RootClass')
-features.catalog.append(modbus_features)
-
-import connectors
-from LPCconnector import LPC_connector_factory
-from LPCconnector.PYRO import MW_PYRO_connector_factory
-from LPCconnector.WAMP import MWWAMP_connector_factory
-
-import targets
-from LPCtarget import LPC_target
-
-targets.targets["LPC"] = {"xsd": os.path.join(_lpcmanager_path, "LPCtarget", "XSD"),
- "class": lambda: LPC_target,
- "code": {os.path.join(_lpcmanager_path, "LPCtarget", "plc_LPC_main.c")}}
-targets.toolchains["makefile"] = os.path.join(_lpcmanager_path, "LPCtarget", "XSD_toolchain_makefile")
-targets.targets["MC9"] = {"xsd": os.path.join(_lpcmanager_path, "MC9target", "XSD"),
- "class": targets.targets["Xenomai"]["class"],
- "code": {"plc_MC9_main.c": targets.targets["Xenomai"]["code"]["plc_Xenomai_main.c"],
- "plc_MC9_main_retain.c": os.path.join(_lpcmanager_path,
- "MC9target", "plc_MC9_main_retain.c")}}
-from BeremizIDE import *
-from ProjectController import ProjectController
-from ConfigTreeNode import ConfigTreeNode
-from editors.ProjectNodeEditor import ProjectNodeEditor
-from editors.ConfTreeNodeEditor import ConfTreeNodeEditor
-from editors.CodeFileEditor import VariablesTable
-from editors.CodeFileEditor import VariablesEditor
-from editors.CodeFileEditor import CodeEditor
-from controls import ProjectPropertiesPanel
-from controls.SearchResultPanel import SearchResultPanel
-# from controls.LogViewer import LogViewer
-from WampOptionsEditor import WampOptionsEditor
-from VariableExporter import VariableWriter
-from PLCControler import PLCControler, ITEMS_UNEDITABLE, ITEM_POU
-from wx.lib.scrolledpanel import ScrolledPanel
-from types import MethodType
-from IDEFrame import IDEFrame
-from dialogs import SearchInProjectDialog
-from controls import TextCtrlAutoComplete
-from py_ext import PythonFileCTNMixin
-from plcopen.structures import TestIdentifier, IDENTIFIER_MODEL
-
-def CTNGenerate_C(self, buildpath, locations):
- # location string for that CTN
- location_str = "_".join(map(lambda x: str(x),
- self.GetCurrentLocation()))
- configname = self.GetCTRoot().GetProjectConfigNames()[0]
-
- pyextname = self.CTNName()
- varinfos = map(lambda variable: {
- "name": variable.getname(),
- "desc": repr(variable.getdesc()),
- "onchangecode": '"' + variable.getonchange() + \
- "('" + variable.getname() + "')\"" \
- if variable.getonchange() else '""',
- "onchange": repr(variable.getonchange()) \
- if variable.getonchange() else None,
- "opts": repr(variable.getopts()),
- "configname": configname.upper(),
- "uppername": variable.getname().upper(),
- "IECtype": variable.gettype(),
- "initial": repr(variable.getinitial()),
- "pyextname": pyextname},
- self.CodeFile.variables.variable)
- # python side PLC global variables access stub
- globalstubs = "\n".join(["""\
-_%(name)s_ctype, _%(name)s_unpack, _%(name)s_pack = \\
- TypeTranslator["%(IECtype)s"]
-_PySafeGetPLCGlob_%(name)s = PLCBinary.__SafeGetPLCGlob_%(name)s
-_PySafeGetPLCGlob_%(name)s.restype = None
-_PySafeGetPLCGlob_%(name)s.argtypes = [ctypes.POINTER(_%(name)s_ctype)]
-_PySafeSetPLCGlob_%(name)s = PLCBinary.__SafeSetPLCGlob_%(name)s
-_PySafeSetPLCGlob_%(name)s.restype = None
-_PySafeSetPLCGlob_%(name)s.argtypes = [ctypes.POINTER(_%(name)s_ctype)]
-_%(pyextname)sGlobalsDesc.append((
- "%(name)s",
- "%(IECtype)s",
- %(initial)s,
- %(desc)s,
- %(onchange)s,
- %(opts)s))
-""" % varinfo
- for varinfo in varinfos])
-
- # Runtime calls (start, stop, init, and cleanup)
- rtcalls = ""
- for section in self.SECTIONS_NAMES:
- if section != "globals":
- rtcalls += "def _runtime_%s_%s():\n" % (location_str, section)
- sectiontext = self.GetSection(section).strip()
- if sectiontext:
- rtcalls += ' ' + \
- sectiontext.replace('\n', '\n ') + "\n\n"
- else:
- rtcalls += " pass\n\n"
-
- globalsection = self.GetSection("globals")
-
- PyFileContent = """\
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-## Code generated by Beremiz python mixin confnode
-##
-
-## Code for PLC global variable access
-from targets.typemapping import TypeTranslator
-import ctypes
-_%(pyextname)sGlobalsDesc = []
-__ext_name__ = "%(pyextname)s"
-PLCGlobalsDesc.append(( "%(pyextname)s" , _%(pyextname)sGlobalsDesc ))
-%(globalstubs)s
-
-## User code in "global" scope
-%(globalsection)s
-
-## Beremiz python runtime calls
-%(rtcalls)s
-
-del __ext_name__
-
-""" % locals()
-
- # write generated content to python file
- runtimefile_path = os.path.join(buildpath,
- "runtime_%s.py" % location_str)
- runtimefile = open(runtimefile_path, 'w')
- runtimefile.write(PyFileContent.encode('utf-8'))
- runtimefile.close()
-
- # C code for safe global variables access
-
- vardecfmt = """\
-extern __IEC_%(IECtype)s_t %(configname)s__%(uppername)s;
-IEC_%(IECtype)s __%(name)s_rbuffer = __INIT_%(IECtype)s;
-IEC_%(IECtype)s __%(name)s_wbuffer;
-long __%(name)s_rlock = 0;
-long __%(name)s_wlock = 0;
-int __%(name)s_wbuffer_written = 0;
-void __SafeGetPLCGlob_%(name)s(IEC_%(IECtype)s *pvalue){
- while(AtomicCompareExchange(&__%(name)s_rlock, 0, 1));
- *pvalue = __%(name)s_rbuffer;
- AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0);
-}
-void __SafeSetPLCGlob_%(name)s(IEC_%(IECtype)s *value){
- while(AtomicCompareExchange(&__%(name)s_wlock, 0, 1));
- __%(name)s_wbuffer = *value;
- __%(name)s_wbuffer_written = 1;
- AtomicCompareExchange((long*)&__%(name)s_wlock, 1, 0);
-}
-
-"""
-
- vardeconchangefmt = """\
-PYTHON_POLL* __%(name)s_notifier;
-"""
-
- varretfmt = """\
- if(!AtomicCompareExchange(&__%(name)s_wlock, 0, 1)){
- if(__%(name)s_wbuffer_written == 1){
- %(configname)s__%(uppername)s.value = __%(name)s_wbuffer;
- __%(name)s_wbuffer_written = 0;
- }
- AtomicCompareExchange((long*)&__%(name)s_wlock, 1, 0);
- }
-"""
- varpubfmt = """\
- if(!AtomicCompareExchange(&__%(name)s_rlock, 0, 1)){
- __%(name)s_rbuffer = __GET_VAR(%(configname)s__%(uppername)s);
- AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0);
- }
-"""
-
- varpubonchangefmt = """\
- if(!AtomicCompareExchange(&__%(name)s_rlock, 0, 1)){
- IEC_%(IECtype)s tmp = __GET_VAR(%(configname)s__%(uppername)s);
- if(__%(name)s_rbuffer != tmp){
- __%(name)s_rbuffer = %(configname)s__%(uppername)s.value;
- PYTHON_POLL_body__(__%(name)s_notifier);
- }
- AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0);
- }
-"""
- varinitonchangefmt = """\
- __%(name)s_notifier = __GET_GLOBAL_ON%(uppername)sCHANGE();
- __SET_VAR(__%(name)s_notifier->,TRIG,,__BOOL_LITERAL(TRUE));
- __SET_VAR(__%(name)s_notifier->,CODE,,__STRING_LITERAL(%(onchangelen)d,%(onchangecode)s));
-"""
- vardec = "\n".join([(vardecfmt + vardeconchangefmt
- if varinfo["onchange"] else vardecfmt) % varinfo
- for varinfo in varinfos])
- varret = "\n".join([varretfmt % varinfo for varinfo in varinfos])
- varpub = "\n".join([(varpubonchangefmt if varinfo["onchange"] else
- varpubfmt) % varinfo
- for varinfo in varinfos])
- varinit = "\n".join([varinitonchangefmt % dict(
- onchangelen=len(varinfo["onchangecode"]), **varinfo)
- for varinfo in varinfos if varinfo["onchange"]])
-
- # TODO : use config name obtained from model instead of default
- # "config.h". User cannot change config name, but project imported
- # or created in older beremiz vesion could use different name.
- PyCFileContent = """\
-/*
- * Code generated by Beremiz py_ext confnode
- * for safe global variables access
- */
-#include "iec_types_all.h"
-#include "POUS.h"
-#include "config.h"
-#include "beremiz.h"
-
-/* User variables reference */
-%(vardec)s
-
-/* Beremiz confnode functions */
-int __init_%(location_str)s(int argc,char **argv){
-%(varinit)s
- return 0;
-}
+from LPCArch import PLC_module, SetLPCArch
+from Beremiz import BeremizIDELauncher
-void __cleanup_%(location_str)s(void){
-}
-
-void __retrieve_%(location_str)s(void){
-%(varret)s
-}
-
-void __publish_%(location_str)s(void){
-%(varpub)s
-}
-""" % locals()
-
- Gen_PyCfile_path = os.path.join(buildpath, "PyCFile_%s.c" % location_str)
- pycfile = open(Gen_PyCfile_path, 'w')
- pycfile.write(PyCFileContent)
- pycfile.close()
-
- matiec_CFLAGS = '"-I%s"' % os.path.abspath(
- self.GetCTRoot().GetIECLibPath())
-
- return ([(Gen_PyCfile_path, matiec_CFLAGS)],
- "",
- True,
- ("runtime_%s.py" % location_str, file(runtimefile_path, "rb")))
-PythonFileCTNMixin.CTNGenerate_C = CTNGenerate_C
-
-def ResetSearchResults(self):
- self.Highlights = []
- self.SearchParams = None
- self.SearchResults = None
- self.VariableSearchResults = []
- self.CurrentFindHighlight = None
- self.index = 0
-CodeEditor.ResetSearchResults = ResetSearchResults
-
-from graphics.GraphicCommons import ERROR_HIGHLIGHT, SEARCH_RESULT_HIGHLIGHT, REFRESH_HIGHLIGHT_PERIOD
-[STC_CODE_ERROR, STC_CODE_SEARCH_RESULT,
- STC_CODE_SECTION] = range(15, 18)
-
-HIGHLIGHT_TYPES = {
- ERROR_HIGHLIGHT: STC_CODE_ERROR,
- SEARCH_RESULT_HIGHLIGHT: STC_CODE_SEARCH_RESULT,
-}
-def FindVariable(self, direction, search_params, variables):
- first = False
- if self.SearchParams != search_params:
- first = True
- self.SearchParams = search_params
- if len(self.VariableSearchResults) > 0:
- (r, c) = self.VariableSearchResults[self.index]
- variables.VariablesGrid.SetCellBackgroundColour(r, c, SEARCH_RESULT_HIGHLIGHT[1])
- grid = variables.VariablesGrid
- cols = grid.GetNumberCols()
- rows = grid.GetNumberRows()
- self.VariableSearchResults = []
- for row in range(rows):
- for col in range(cols):
- value = variables.VariablesGrid.GetCellValue(row, col)
- search_value = search_params['find_pattern']
- if search_params['case_sensitive'] == False:
- search_value = search_value.lower()
- value = value.lower()
- if search_value in value:
- self.VariableSearchResults.append((row, col))
- self.index = 0
- if len(self.VariableSearchResults) > 0:
- (r, c) = self.VariableSearchResults[self.index]
- variables.VariablesGrid.SetCellBackgroundColour(r, c, SEARCH_RESULT_HIGHLIGHT[1])
- if not first:
- self.index += direction
- self.index = self.index % len(self.VariableSearchResults)
- (r, c) = self.VariableSearchResults[self.index]
- variables.VariablesGrid.SetCellBackgroundColour(r, c, SEARCH_RESULT_HIGHLIGHT[0])
- variables.VariablesGrid.MakeCellVisible(r, c)
- variables.VariablesGrid.ForceRefresh()
-CodeEditor.FindVariable = FindVariable
-
-def SearchInPyfile(self, criteria):
- result = []
- from xml.dom import minidom
- dir_list = next(os.walk(self.ProjectPath))[1]
- for dir in dir_list:
- if dir not in ["build", "CanOpen@CanOpen", "project_files"]:
- path = os.path.join(self.ProjectPath, dir, 'pyfile.xml')
- variablelist = []
- if os.path.exists(path):
- pyfile = minidom.parse(path)
- variablelist = pyfile.getElementsByTagName('variable')
- for s in variablelist:
- if criteria["find_pattern"] in s.attributes['name'].value:
- result.append(dir)
- return result
-PLCControler.SearchInPyfile = SearchInPyfile
-
-def OnSearchInProjectMenu(self, event):
- dialog = SearchInProjectDialog(self)
- if dialog.ShowModal() == wx.ID_OK:
- criteria = dialog.GetCriteria()
- if len(criteria) > 0:
- result = self.Controler.SearchInProject(criteria)
- pyresult = self.Controler.SearchInPyfile(criteria)
- self.ClearSearchResults()
- self.SearchResultPanel.SetSearchResults(criteria, result, pyresult)
- self.SearchResultPanel.AddPyFileResults(pyresult)
- self.SelectTab(self.SearchResultPanel)
-IDEFrame.OnSearchInProjectMenu = OnSearchInProjectMenu
-
-def GenerateProjectTreeBranch(self, root, infos, item_alone=False):
- to_delete = []
- item_name = infos["name"]
- if infos["type"] in ITEMS_UNEDITABLE:
- if len(infos["values"]) == 1:
- return self.GenerateProjectTreeBranch(root, infos["values"][0], True)
- item_name = _(item_name)
- self.ProjectTree.SetItemText(root, item_name)
- self.ProjectTree.SetPyData(root, infos)
- highlight_colours = self.Highlights.get(infos.get("tagname", None), (wx.WHITE, wx.BLACK))
- self.ProjectTree.SetItemBackgroundColour(root, highlight_colours[0])
- self.ProjectTree.SetItemTextColour(root, highlight_colours[1])
- self.ProjectTree.SetItemExtraImage(root, None)
- if infos["type"] == ITEM_POU:
- self.ProjectTree.SetItemImage(root,
- self.TreeImageDict[self.Controler.GetPouBodyType(infos["name"])])
- if item_alone:
- self.ProjectTree.SetItemExtraImage(root, self.Controler.GetPouType(infos["name"]))
- elif infos.has_key("icon") and infos["icon"] is not None:
- icon_name = infos["icon"]
- if not self.TreeImageDict.has_key(icon_name):
- self.TreeImageDict[icon_name] = self.TreeImageList.Add(GetBitmap(icon_name))
- self.ProjectTree.SetItemImage(root, self.TreeImageDict[icon_name])
- elif self.TreeImageDict.has_key(infos["type"]):
- self.ProjectTree.SetItemImage(root, self.TreeImageDict[infos["type"]])
-
- item, root_cookie = self.ProjectTree.GetFirstChild(root)
- for values in infos["values"]:
- if values["type"] not in ITEMS_UNEDITABLE or len(values["values"]) > 0:
- if item is None or not item.IsOk():
- item = self.ProjectTree.AppendItem(root, "")
- item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
- self.GenerateProjectTreeBranch(item, values)
- item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
- while item is not None and item.IsOk():
- to_delete.append(item)
- item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
- for item in to_delete:
- self.ProjectTree.Delete(item)
-IDEFrame.GenerateProjectTreeBranch = GenerateProjectTreeBranch
-
-defaultSearchResultPanelInit = SearchResultPanel.__init__
-def SearchResultPanelInit(self, parent, window):
- defaultSearchResultPanelInit(self, parent, window)
- self.TreeImageDict["py_file"] = self.TreeImageList.Add(GetBitmap("py_file"))
- self.TreeImageDict["wx_glade"] = self.TreeImageList.Add(GetBitmap("wx_glade"))
-SearchResultPanel.__init__ = SearchResultPanelInit
-
-def SetSearchResults(self, criteria, search_results, py_results):
- self.Criteria = criteria
- self.SearchResults = {}
- self.ElementsOrder = []
- self.PySearchResults = py_results
-
- for infos, start, end, text in search_results:
- if infos[0] not in self.ElementsOrder:
- self.ElementsOrder.append(infos[0])
-
- results = self.SearchResults.setdefault(infos[0], [])
- results.append((infos, start, end, text))
-
- self.RefreshView()
-SearchResultPanel.SetSearchResults = SetSearchResults
-
-def AddPyFileResults(self, search_results):
- distinct_list = list(set(search_results))
- for result in distinct_list:
- name = result.split('@')
- matches = search_results.count(result)
- if name[1] == "py_ext":
- root = self.SearchResultsTree.GetRootItem()
- self.SearchResultsTree.AppendItem(root, name[0], image=self.TreeImageDict["py_file"])
- else:
- root = self.SearchResultsTree.GetRootItem()
- self.SearchResultsTree.AppendItem(root, name[0], image=self.TreeImageDict["wx_glade"])
- if matches > 1:
- text = _("(%d matches)") % search_results.count(result)
- start_idx, end_idx = 0, len(text)
- style = wx.TextAttr(wx.Colour(0, 127, 174))
- text_ctrl_style = wx.BORDER_NONE | wx.TE_READONLY | wx.TE_RICH2
- if wx.Platform != '__WXMSW__' or len(text.splitlines()) > 1:
- text_ctrl_style |= wx.TE_MULTILINE
- text_ctrl = wx.TextCtrl(id=-1, parent=self.SearchResultsTree, pos=wx.Point(0, 0),
- value=text, style=text_ctrl_style)
- width, height = text_ctrl.GetTextExtent(text)
- text_ctrl.SetClientSize(wx.Size(width + 1, height))
- text_ctrl.SetBackgroundColour(self.SearchResultsTree.GetBackgroundColour())
- child = self.SearchResultsTree.GetLastChild(root)
- text_ctrl.SetInsertionPoint(0)
- text_ctrl.SetStyle(start_idx, end_idx, style)
- self.SearchResultsTree.SetItemWindow(child, text_ctrl)
-SearchResultPanel.AddPyFileResults = AddPyFileResults
-
-
-def ResetSearchResults(self):
- self.Criteria = None
- self.ElementsOrder = []
- self.SearchResults = {}
- self.PySearchResults = []
- self.RefreshView()
-SearchResultPanel.ResetSearchResults = ResetSearchResults
-
-
-def GetPythonTextCtrlDClickFunction(self, item):
- for type in self.ParentWindow.CTR.Children.values():
- for name in type:
- if name.BaseParams.attrib['Name'] == item:
- name._OpenView()
- selected = self.ParentWindow.TabsOpened.GetSelection()
- if selected != -1:
- window = self.ParentWindow.TabsOpened.GetPage(selected)
- window.CodeEditor.FindVariable(1, {'find_pattern': self.Criteria['find_pattern'],
- 'regular_expression': self.Criteria['regular_expression'],
- 'pattern': self.Criteria['pattern'],
- 'case_sensitive': self.Criteria['case_sensitive'],
- 'filter': self.Criteria['filter']}, window.VariablesPanel)
- for (r, c) in window.CodeEditor.VariableSearchResults:
- window.VariablesPanel.VariablesGrid.SetCellBackgroundColour(r, c,
- SEARCH_RESULT_HIGHLIGHT[0])
-SearchResultPanel.GetPythonTextCtrlDClickFunction = GetPythonTextCtrlDClickFunction
-
-
-def OnSearchResultsTreeItemActivated(self, event):
- self.ShowSearchResults(event.GetItem())
- if event.GetItem()._data is None:
- self.GetPythonTextCtrlDClickFunction(event.GetItem()._text)
- event.Skip()
-SearchResultPanel.OnSearchResultsTreeItemActivated = OnSearchResultsTreeItemActivated
-
-defaultProjectPropertiesPanelInit = ProjectPropertiesPanel.__init__
-def OurProjectPropertiesPanelInit(self, parent, controller=None, window=None, enable_required=True):
-
- REQUIRED_PARAMS = ["projectName", "productName", "productVersion", "companyName"]
- [TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE,
- POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES
- ] = range(10)
-
- def create_project_panel(self):
- self.ProjectPanel = ScrolledPanel(self, -1, style=wx.TAB_TRAVERSAL)
- self.ProjectPanel.SetAutoLayout(1)
- self.ProjectPanel.SetupScrolling()
- self.AddPage(self.ProjectPanel, _("Project"))
-
- projectpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=5, vgap=15)
- projectpanel_sizer.AddGrowableCol(1)
- self.ProjectPanel.SetSizer(projectpanel_sizer)
-
- self.AddSizerParams(self.ProjectPanel, projectpanel_sizer,
- [("projectName", _('Project Name (required):')),
- ("projectVersion", _('Project Version (optional):')),
- ("productName", _('Product Name (required):')),
- ("productVersion", _('Product Version (required):')),
- ("productRelease", _('Product Release (optional):'))])
-
- self.AddPage(self.ProjectPanel, _("Project"))
-
- def create_author_panel(self):
- 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)
-
- self.AddSizerParams(self.AuthorPanel, authorpanel_sizer,
- [("companyName", _('Company Name (required):')),
- ("companyURL", _('Company URL (optional):')),
- ("authorName", _('Author Name (optional):')),
- ("organization", _('Organization (optional):'))])
-
- self.AddPage(self.AuthorPanel, _("Author"))
-
- def create_graphic_panel(self):
- 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)
- self.GraphicsPanel.SetSizer(graphicpanel_sizer)
-
- pageSize_st = wx.StaticText(self.GraphicsPanel,
- label=_('Page Size (optional):'))
- graphicpanel_sizer.AddWindow(pageSize_st, border=10,
- flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.LEFT | wx.RIGHT)
-
- pageSize_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5)
- pageSize_sizer.AddGrowableCol(1)
- graphicpanel_sizer.AddSizer(pageSize_sizer, border=10,
- flag=wx.GROW | wx.LEFT | wx.RIGHT)
-
- for name, label in [('PageWidth', _('Width:')), ('PageHeight', _('Height:'))]:
- st = wx.StaticText(self.GraphicsPanel, label=label)
- pageSize_sizer.AddWindow(st, border=12,
- flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT)
-
- sp = wx.SpinCtrl(self.GraphicsPanel,
- min=0, max=2 ** 16, style=wx.TE_PROCESS_ENTER)
- setattr(self, name, sp)
- callback = self.GetPageSizeChangedFunction(sp, name)
- self.Bind(wx.EVT_TEXT_ENTER, callback, sp)
- sp.Bind(wx.EVT_KILL_FOCUS, callback)
- pageSize_sizer.AddWindow(sp, flag=wx.GROW)
+class LPCManagerLauncher(BeremizIDELauncher):
+ def __init__(self):
+ BeremizIDELauncher.__init__(self)
+ self.arch = None
+ self.port = None
+ self.extensions = [os.path.join(_lpcmanager_path, "LPCExtension.py")]
+ self.modules.extend([
+ "LPCBeremiz",
+ "StdoutPseudoFile",
+ "LPCProjectController",
+ "LPCCommand"])
- scaling_st = wx.StaticText(self.GraphicsPanel,
- label=_('Grid Resolution:'))
- graphicpanel_sizer.AddWindow(scaling_st, border=10,
- flag=wx.GROW | wx.LEFT | wx.RIGHT)
-
- scaling_nb = wx.Notebook(self.GraphicsPanel)
- graphicpanel_sizer.AddWindow(scaling_nb, border=10,
- flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT)
-
- self.Scalings = {}
- for language, translation in [("FBD", _("FBD")), ("LD", _("LD")), ("SFC", _("SFC"))]:
- scaling_panel = wx.Panel(scaling_nb, style=wx.TAB_TRAVERSAL)
- scalingpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5)
- scalingpanel_sizer.AddGrowableCol(1)
- scaling_panel.SetSizer(scalingpanel_sizer)
-
- scaling_controls = []
- for idx, (name, label) in enumerate([('XScale', _('Horizontal:')),
- ('YScale', _('Vertical:'))]):
- if idx == 0:
- border = wx.TOP
- else:
- border = wx.BOTTOM
-
- st = wx.StaticText(scaling_panel, label=label)
- scalingpanel_sizer.AddWindow(st, border=10,
- flag=wx.ALIGN_CENTER_VERTICAL | border | wx.LEFT)
-
- sp = wx.SpinCtrl(scaling_panel,
- min=0, max=2 ** 16, style=wx.TE_PROCESS_ENTER)
- scaling_controls.append(sp)
- callback = self.GetScalingChangedFunction(sp, language, name)
- self.Bind(wx.EVT_TEXT_ENTER, callback, sp)
- sp.Bind(wx.EVT_KILL_FOCUS, callback)
- scalingpanel_sizer.AddWindow(sp, border=10,
- flag=wx.GROW | border | wx.RIGHT)
-
- self.Scalings[language] = scaling_controls
- scaling_nb.AddPage(scaling_panel, translation)
-
- self.AddPage(self.GraphicsPanel, _("Graphics"))
-
- def create_miscellaneous_panel(self):
- 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)
- self.MiscellaneousPanel.SetSizer(miscellaneouspanel_sizer)
-
- language_label = wx.StaticText(self.MiscellaneousPanel,
- label=_('Language (optional):'))
- miscellaneouspanel_sizer.AddWindow(language_label, border=10,
- flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.LEFT)
-
- self.Language = wx.ComboBox(self.MiscellaneousPanel,
- style=wx.CB_READONLY)
- self.Bind(wx.EVT_COMBOBOX, self.OnLanguageChanged, self.Language)
- miscellaneouspanel_sizer.AddWindow(self.Language, border=10,
- flag=wx.GROW | wx.TOP | wx.RIGHT)
-
- description_label = wx.StaticText(self.MiscellaneousPanel,
- label=_('Content Description (optional):'))
- miscellaneouspanel_sizer.AddWindow(description_label, border=10,
- flag=wx.BOTTOM | wx.LEFT)
-
- self.ContentDescription = wx.TextCtrl(self.MiscellaneousPanel,
- style=wx.TE_MULTILINE | wx.TE_PROCESS_ENTER)
- self.Bind(wx.EVT_TEXT_ENTER, self.OnContentDescriptionChanged,
- self.ContentDescription)
- self.ContentDescription.Bind(wx.EVT_KILL_FOCUS,
- self.OnContentDescriptionChanged)
- miscellaneouspanel_sizer.AddWindow(self.ContentDescription, border=10,
- flag=wx.GROW | wx.BOTTOM | wx.RIGHT)
-
- self.AddPage(self.MiscellaneousPanel, _("Miscellaneous"))
-
- wx.Notebook.__init__(self, parent, size=wx.Size(500, 300))
-
- self.Controller = controller
- self.ParentWindow = window
- self.Values = None
-
- create_project_panel(self)
-
- create_author_panel(self)
-
- create_graphic_panel(self)
-
- create_miscellaneous_panel(self)
-
- for param in REQUIRED_PARAMS:
- getattr(self, param).Enable(enable_required)
- languages = ["", "en-US", "fr-FR", "zh-CN", "ru-RU"]
- for language in languages:
- self.Language.Append(language)
-ProjectPropertiesPanel.__init__ = OurProjectPropertiesPanelInit
-
-
-def LeftClick(self, event):
- if event.GetCol() == self.grid.GetNumberCols()-1:
- options = [self.grid.GetCellValue(event.GetRow(), event.GetCol()), self.grid.GetCellValue(event.GetRow(), event.GetCol()-1)]
- desc = self.grid.GetCellValue(event.GetRow(), event.GetCol()-2)
- if hasattr(self, "dialog"):
- self.dialog.SetOptions(options, desc)
- answer = self.dialog.ShowModal()
- #self.dialog.SetOptions(options, desc)
- else:
- self.dialog = WampOptionsEditor(self.Parent.Parent, options, desc)
- answer = self.dialog.ShowModal()
- opt,OnChange,value,description = self.dialog.GetOptions()
- if answer == wx.ID_OK:
- self.grid.SetCellValue(event.GetRow(), event.GetCol(), str(opt))
- if OnChange:
- self.grid.SetCellValue(event.GetRow(), event.GetCol()-1, value)
- self.grid.SetCellValue(event.GetRow(), event.GetCol()-2, description)
- self.Parent.RefreshModel()
-
- else:
- event.Skip()
-VariablesTable.LeftClick = LeftClick
-
-def VariablesEditorSetCollSize(self):
- ColSizes = [20, 150] + [130] * (len(self.VariablesDefaultValue) - 2) + [300]
- for col in range(self.Table.GetNumberCols()):
- self.VariablesGrid.SetColSize(col, ColSizes[col])
-VariablesEditor.VariablesEditorSetCollSize = VariablesEditorSetCollSize
-
-def _updateColAttrs(self, grid):
- """
- wxGrid -> update the column attributes to add the
- appropriate renderer given the column name.
-
- Otherwise default to the default renderer.
- """
- typelist = None
- accesslist = None
- self.grid = grid
- for row in range(self.GetNumberRows()):
- for col in range(self.GetNumberCols()):
- editor = None
- renderer = None
- colname = self.GetColLabelValue(col, False)
-
- if colname in ["Name", "Initial", "Description", "OnChange"]:
- editor = wx.grid.GridCellTextEditor()
- elif colname == "Class":
- editor = wx.grid.GridCellChoiceEditor()
- editor.SetParameters("input,memory,output")
- elif colname == "Type":
- pass
- else:
- grid.SetReadOnly(row, col, True)
-
- grid.SetCellEditor(row, col, editor)
- grid.SetCellRenderer(row, col, renderer)
-
- grid.SetCellBackgroundColour(row, col, wx.WHITE)
-
- self.grid.SetRowMinimalHeight
- # updated column width, with function VariablesEditorSetCollSize added in VariablesEditor class
- self.Parent.VariablesEditorSetCollSize()
- # added left click option on grid, with function LeftClick added in VariablesTable class
- self.grid.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.LeftClick)
-VariablesTable._updateColAttrs = _updateColAttrs
-
-"""Zakomentirano ker je ze v beremiz-u"""
-# def OnCleanButton(self, event):
-# if self.LogSource is not None:
-# rez = self.LogSource.ResetLogCount()
-# if not rez:
-# self.GrandParent.CTR.logger.write_warning("Can not reset log messages!\n")
-# self.ResetLogMessages()
-# self.RefreshView()
-# event.Skip()
-# LogViewer.OnCleanButton = OnCleanButton
-
-from PLCControler import PLCControler, LOCATION_MODULE, LOCATION_GROUP
-
-defaultGenerateNewName = PLCControler.GenerateNewName
-def newGenerateNewName(self, tagname, name, format, start_idx=0, exclude={}, debug=False):
- if tagname:
- return defaultGenerateNewName(self, tagname, name, format, start_idx=0, exclude={}, debug=False)
- else:
- names = exclude.copy()
- i = start_idx
- while name is None or names.get(name.upper(), False):
- name = (format%i)
- i += 1
- return name
-PLCControler.GenerateNewName = newGenerateNewName
-
-
-havecanfestival = False
-# try:
-from canfestival import RootClass as CanOpenRootClass
-from canfestival.canfestival import _SlaveCTN, _NodeListCTN, NodeManager
-from canfestival.NetworkEditor import NetworkEditor
-from canfestival.SlaveEditor import SlaveEditor
-
-havecanfestival = True
-# except:
-# havecanfestival = False
-
-SCROLLBAR_UNIT = 10
-ID_EXPORT = 7500
-WINDOW_COLOUR = wx.Colour(240, 240, 240)
-TITLE_COLOUR = wx.Colour(200, 200, 220)
-CHANGED_TITLE_COLOUR = wx.Colour(220, 200, 220)
-CHANGED_WINDOW_COLOUR = wx.Colour(255, 240, 240)
-
-if wx.Platform == '__WXMSW__':
- faces = {'times': 'Times New Roman',
- 'mono': 'Courier New',
- 'helv': 'Arial',
- 'other': 'Comic Sans MS',
- 'size': 16,
- }
-else:
- faces = {'times': 'Times',
- 'mono': 'Courier',
- 'helv': 'Helvetica',
- 'other': 'new century schoolbook',
- 'size': 18,
- }
-
-# ConfTreeNodeEditor.SHOW_BASE_PARAMS = False
-
-# -------------------------------------------------------------------------------
-# CANFESTIVAL CONFNODE HACK
-# -------------------------------------------------------------------------------
-from canfestival import canfestival
-defaultGetCFLAGS = canfestival.local_canfestival_config.getCFLAGS
-defaultGetLDFLAGS = canfestival.local_canfestival_config.getLDFLAGS
-
-def getCFLAGS(*args):
- return str(defaultGetCFLAGS(*args))
-
-def getLDFLAGS(*args):
- return str(defaultGetLDFLAGS(*args))
-
-canfestival.local_canfestival_config.getCFLAGS = getCFLAGS
-canfestival.local_canfestival_config.getLDFLAGS = getLDFLAGS
-
-import LPCBus as LPCBus_mod
-
-if arch in PLC_module:
- LPCBus_mod.LPCarch = "MC9"
- LPCBus_mod.arch = arch
-else:
- LPCBus_mod.LPCarch = arch
- LPCBus_mod.arch = arch
-
-from LPCBus import *
-
-# -------------------------------------------------------------------------------
-# LPC CanFestival ConfNode Class
-# -------------------------------------------------------------------------------
-
-if havecanfestival:
- DEFAULT_SETTINGS = {
- "CAN_Baudrate": "125K",
- "Slave_NodeId": 2,
- "Master_NodeId": 1,
- }
-
-
-class LPCSlaveEditor(SlaveEditor):
- # SHOW_BASE_PARAMS = False
- pass
-
-
-class LPCCanOpenSlave(_SlaveCTN):
- XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
- <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <xsd:element name="CanFestivalSlaveNode">
- <xsd:complexType>
- <xsd:attribute name="CAN_Baudrate" type="xsd:string" use="optional" default="%(CAN_Baudrate)s"/>
- <xsd:attribute name="NodeId" type="xsd:integer" use="optional" default="%(Slave_NodeId)d"/>
- <xsd:attribute name="Sync_Align" type="xsd:integer" use="optional" default="0"/>
- <xsd:attribute name="Sync_Align_Ratio" use="optional" default="50">
- <xsd:simpleType>
- <xsd:restriction base="xsd:integer">
- <xsd:minInclusive value="1"/>
- <xsd:maxInclusive value="99"/>
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:attribute>
- </xsd:complexType>
- </xsd:element>
- </xsd:schema>
- """ % DEFAULT_SETTINGS
-
- EditorType = LPCSlaveEditor
+ def Usage(self):
+ print("\nUsage of LPCManager.py :")
+ print("\n %s Projectpath Buildpath port arch\n" % sys.argv[0])
- def __init__(self):
- # TODO change netname when name change
- NodeManager.__init__(self)
- odfilepath = self.GetSlaveODPath()
- if (os.path.isfile(odfilepath)):
- self.OpenFileInCurrent(odfilepath)
- else:
- self.CreateNewNode("SlaveNode", # Name - will be changed at build time
- 0x00, # NodeID - will be changed at build time
- "slave", # Type
- "", # description
- "None", # profile
- "", # prfile filepath
- "heartbeat", # NMT
- []) # options
- self.OnCTNSave()
-
- def GetCanDevice(self):
- return str(self.BaseParams.getIEC_Channel())
-
- ConfNodeMethods = [
- {"bitmap": "NetworkEdit",
- "name": _("Edit slave"),
- "tooltip": _("Edit CanOpen slave with ObjdictEdit"),
- "method": "_OpenView"},
- ] + _SlaveCTN.ConfNodeMethods
-
-
-class LPCNetworkEditor(NetworkEditor):
- # SHOW_BASE_PARAMS = False
- pass
-
-
-class LPCCanOpenMaster(_NodeListCTN):
- XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
- <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <xsd:element name="CanFestivalNode">
- <xsd:complexType>
- <xsd:attribute name="CAN_Baudrate" type="xsd:string" use="optional" default="%(CAN_Baudrate)s"/>
- <xsd:attribute name="NodeId" type="xsd:integer" use="optional" default="%(Master_NodeId)d"/>
- <xsd:attribute name="Sync_TPDOs" type="xsd:boolean" use="optional" default="true"/>
- </xsd:complexType>
- </xsd:element>
- </xsd:schema>
- """ % DEFAULT_SETTINGS
-
- EditorType = LPCNetworkEditor
-
- def GetCanDevice(self):
- return str(self.BaseParams.getIEC_Channel())
-
- ConfNodeMethods = [
- {"bitmap": "NetworkEdit",
- "name": _("Edit network"),
- "tooltip": _("Edit CanOpen Network with NetworkEdit"),
- "method": "_OpenView"},
- ] + _NodeListCTN.ConfNodeMethods
-
-
-class LPCCanOpen(CanOpenRootClass):
- XSD = None
- CTNChildrenTypes = [("CanOpenNode", LPCCanOpenMaster, "CanOpen Master"),
- ("CanOpenSlave", LPCCanOpenSlave, "CanOpen Slave")]
-
- def GetCanDriver(self):
- return None
-
- def LoadChildren(self):
- ConfigTreeNode.LoadChildren(self)
-
- if self.GetChildByName("Master") is None:
- master = self.CTNAddChild("Master", "CanOpenNode", 0)
- # master.BaseParams.setEnabled(False)
- master.CTNRequestSave()
-
- if self.GetChildByName("Slave") is None:
- slave = self.CTNAddChild("Slave", "CanOpenSlave", 1)
- # slave.BaseParams.setEnabled(False)
- slave.CTNRequestSave()
-
-# -------------------------------------------------------------------------------
-# LPCProjectController Class
-# -------------------------------------------------------------------------------
-
-def mycopytree(src, dst):
- """
- Copy content of a directory to an other, omit hidden files
- @param src: source directory
- @param dst: destination directory
- """
- for i in os.listdir(src):
- if not i.startswith('.'):
- srcpath = os.path.join(src, i)
- dstpath = os.path.join(dst, i)
- if os.path.isdir(srcpath):
- if os.path.exists(dstpath):
- shutil.rmtree(dstpath)
- os.makedirs(dstpath)
- mycopytree(srcpath, dstpath)
- elif os.path.isfile(srcpath):
- shutil.copy2(srcpath, dstpath)
-
-
-[SIMULATION_MODE, TRANSFER_MODE] = range(2)
-
-if arch in PLC_module:
- class LPCProjectNodeEditor(ProjectNodeEditor):
- pass
-else:
- class LPCProjectNodeEditor(ProjectNodeEditor):
- SHOW_PARAMS = False
- ENABLE_REQUIRED = False
+ def ProcessCommandLineArgs(self):
+ # Command line arguments parsing
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
+ except getopt.GetoptError:
+ # print help information and exit:
+ self.Usage()
+ sys.exit(2)
-_StatusMethods = [
- {"bitmap": "Debug",
- "name": _("Simulate"),
- "tooltip": _("Simulate PLC"),
- "method": "_Simulate"},
- {"bitmap": "Run",
- "name": _("Run"),
- "shown": False,
- "tooltip": _("Start PLC"),
- "method": "_Run"},
- {"bitmap": "Stop",
- "name": _("Stop"),
- "shown": False,
- "tooltip": _("Stop Running PLC"),
- "method": "_Stop"},
- {"bitmap": "Build",
- "name": _("Build"),
- "tooltip": _("Build project into build folder"),
- "method": "_Build"},
- {"bitmap": "Clean",
- "name": _("Clean"),
- "enabled": False,
- "tooltip": _("Clean project build folder"),
- "method": "_Clean"},
- {"bitmap": "Transfer",
- "name": _("Transfer"),
- "shown": False,
- "tooltip": _("Transfer PLC"),
- "method": "_Transfer"},
-]
-_MethodFromPLCState = {
- "Started": [("_Simulate", False),
- ("_Run", False),
- ("_Stop", True),
- ("_Build", True),
- ("_Transfer", True)],
- "Stopped": [("_Simulate", False),
- ("_Run", True),
- ("_Stop", False),
- ("_Build", True),
- ("_Transfer", True)],
- "Connected": [("_Simulate", "not simulating"),
- ("_Run", True),
- ("_Stop", True if arch in PLC_module else "simulating"),
- ("_Build", True),
- ("_Transfer", True)],
- "Disconnected": [("_Simulate", "not simulating"),
- ("_Run", False),
- ("_Stop", False if arch in PLC_module else "simulating"),
- ("_Build", True),
- ("_Transfer", False)],
- "Empty" :[("_Simulate", "not simulating"),
- ("_Run", False),
- ("_Stop", False),
- ("_Build", True),
- ("_Transfer", True)],
-}
-
-if arch in PLC_module:
- _StatusMethods += [
- {"bitmap": "Connect",
- "name": _("Connect"),
- "shown": True,
- "tooltip": _("Connect to the target PLC"),
- "method": "_Connect"},
- {"bitmap": "Disconnect",
- "name": _("Disconnect"),
- "shown": False,
- "tooltip": _("Disconnect from PLC"),
- "method": "_Disconnect"},
- {"bitmap": "UpdateFw",
- "name": _("UpdateFw"),
- "shown": True,
- "tooltip": _("Update the PLC firmware"),
- "method": "_UpdateFw"},
- ]
- _MethodFromPLCState["Disconnected"] += [("_Connect", True),
- ("_Disconnect", False)]
-
- _MethodFromPLCState["Connected"] += [("_Connect", False),
- ("_Disconnect", True)]
-
-class LPCProjectController(ProjectController):
- StatusMethods = _StatusMethods
- # ConfNodeMethods = []
-
- EditorType = LPCProjectNodeEditor
-
- def __init__(self, frame, logger, buildpath):
- self.arch = arch
- self.OrigBuildPath = buildpath
-
- ProjectController.__init__(self, frame, logger)
-
- if havecanfestival:
- self.CTNChildrenTypes += [("LPCBus", LPCBus, "LPC bus"), ("CanOpen", LPCCanOpen, "CanOpen bus")]
- else:
- self.CTNChildrenTypes += [("LPCBus", LPCBus, "LPC bus")]
- self.CTNType = "LPC"
-
- self.OnlineMode = "NORMAL" if arch in PLC_module else "OFF"
- self.LPCConnector = None
- self.ConnectorPath = None
-
- self.CurrentMode = None
- self.previous_mode = None
-
- self.SimulationBuildPath = None
-
- self.AbortTransferTimer = None
-
- # Firmware update running status
- self.firmawreUpadateIsRunning = False
- self.building = False
-
-
- # Bind mouse double click event on URI_location in Beremiz
- self.UriOptions = True
-
- def GetProjectName(self):
- return self.Project.getname()
-
- def GetDefaultTargetName(self):
- if self.CurrentMode == SIMULATION_MODE:
- return ProjectController.GetDefaultTargetName(self)
- else:
- return "LPC"
-
- def GetTarget(self):
- target = ProjectController.GetTarget(self)
- if self.CurrentMode != SIMULATION_MODE and arch not in PLC_module:
- target.getcontent().setBuildPath(self.BuildPath)
- return target
-
- def _getBuildPath(self):
- if self.CurrentMode == SIMULATION_MODE:
- if self.SimulationBuildPath is None:
- self.SimulationBuildPath = os.path.join(tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build")
- return self.SimulationBuildPath
- else:
- return ProjectController._getBuildPath(self)
-
- def ToZIPFile(self):
- # MD5 = self.GetLastBuildMD5()
- try:
- path_export_file = self.BuildPath[:-5] + "\\" + self._builder.exe[:-3] + ".xEye"
- zf = zipfile.ZipFile(path_export_file, mode='w', compression=zipfile.ZIP_DEFLATED)
- for extrafilespath in [self._getExtraFilesPath(),
- self._getProjectFilesPath()]:
- dir = extrafilespath.split("\\")[-1]
- for name in os.listdir(extrafilespath):
- zf.write(extrafilespath + '\\' + str(name), dir + '\\' + str(name), zipfile.ZIP_DEFLATED)
- zf.write(self._builder.exe_path, self._builder.exe)
- zf.write(self.BuildPath + '\\lastbuildPLC.md5', 'lastbuildPLC.md5')
- zf.close()
- self.logger.write(_("Export file is successfully created on location: %s\n") % path_export_file)
- except Exception, e:
- self.logger.write(_("Export file is not created because eror: %s\n") % e)
-
- def _Build(self):
- self._Clean()
- save = self.ProjectTestModified()
- if save:
- self.SaveProject()
- self.AppFrame._Refresh(TITLE, FILEMENU)
- if self.BuildPath is not None:
- mycopytree(self.OrigBuildPath, self.BuildPath)
- if ProjectController._Build(self):
- self.ToZIPFile()
- if save:
- wx.CallAfter(self.AppFrame.RefreshAll)
-
- def SetProjectName(self, name):
- return self.Project.setname(name)
-
- def SetOnlineMode(self, mode, path=None):
- # SetOnlineMode is only for MC8
- if arch in PLC_module:
- return None
-
- mode = mode.upper()
- if self.OnlineMode != mode:
- if mode not in ["OFF", ""]:
- self.OnlineMode = mode
- self.ConnectorPath = path
- uri = "LPC://%s/%s" % (self.OnlineMode, path)
- try:
- self.LPCConnector = connectors.ConnectorFactory(uri, self)
- except Exception, msg:
- self.logger.write_error(_("Exception while connecting %s!\n") % uri)
- self.logger.write_error(traceback.format_exc())
-
- # Did connection success ?
- if self.LPCConnector is None:
- # Oups.
- self.logger.write_error(_("Connection failed to %s!\n") % uri)
-
- else:
- self.OnlineMode = "OFF"
- self.LPCConnector = None
- self.ConnectorPath = None
-
- self.ApplyOnlineMode()
-
-
- def ApplyOnlineMode(self):
- if self.CurrentMode != SIMULATION_MODE:
- self.KillDebugThread()
-
- self._SetConnector(self.LPCConnector)
-
- # Init with actual PLC status and print it
- self.UpdateMethodsFromPLCStatus()
-
- if self.LPCConnector is not None and self.OnlineMode == "APPLICATION":
-
- self.CompareLocalAndRemotePLC()
+ # asking for help causes exit
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ self.Usage()
+ sys.exit()
- if self.previous_plcstate is not None:
- status = _(self.previous_plcstate)
- else:
- status = ""
- self.logger.write(_("PLC is %s\n") % status)
-
- # if self.StatusTimer and not self.StatusTimer.IsRunning():
- # # Start the status Timer
- # self.StatusTimer.Start(milliseconds=2000, oneShot=False)
-
- if self.previous_plcstate == "Started":
- if self.DebugAvailable() and self.GetIECProgramsAndVariables():
- self.logger.write(_("Debug connect matching running PLC\n"))
- self._connect_debug()
- else:
- self.logger.write_warning(_("Debug do not match PLC - stop/transfert/start to re-enable\n"))
-
- elif self.StatusTimer and self.StatusTimer.IsRunning():
- self.StatusTimer.Stop()
-
- if self.CurrentMode == TRANSFER_MODE:
-
- if self.OnlineMode == "BOOTLOADER":
- self.BeginTransfer()
-
- elif self.OnlineMode == "APPLICATION":
- self.CurrentMode = None
- self.AbortTransferTimer.Stop()
- self.AbortTransferTimer = None
-
- self.logger.write(_("PLC transferred successfully\n"))
-
- # Update a PLCOpenEditor Pou variable location
- def UpdateProjectVariableLocation(self, old_leading, new_leading):
- self.Project.updateElementAddress(old_leading, new_leading)
- self.BufferProject()
-
- # Update a PLCOpenEditor Pou variable name
- def UpdateProjectVariableName(self, old_name, new_name):
- self.Project.updateElementName(old_name, new_name)
- self.BufferProject()
-
- def RemoveProjectVariableByAddress(self, address):
- self.Project.removeVariableByAddress(address)
- self.BufferProject()
-
- def RemoveProjectVariableByFilter(self, leading):
- self.Project.removeVariableByFilter(leading)
- self.BufferProject()
-
- def AddProjectDefaultConfiguration(self, config_name="config", res_name="resource1"):
- ProjectController.AddProjectDefaultConfiguration(self, config_name, res_name)
-
- self.SetEditedResourceInfos(
- self.ComputeConfigurationResourceName(config_name, res_name),
- [{"Name": "main_task",
- "Triggering": "Cyclic",
- "Interval": "T#50ms",
- "Priority": 0}],
- [])
-
- def LoadProject(self, ProjectPath, BuildPath=None):
- """
- Load a project contained in a folder
- @param ProjectPath: path of the project folder
- """
- if os.path.basename(ProjectPath) == "":
- ProjectPath = os.path.dirname(ProjectPath)
-
- # Verify that project contains a PLCOpen program
- plc_file = os.path.join(ProjectPath, "plc.xml")
- if os.path.isfile(plc_file):
- # Load PLCOpen file
- result = self.OpenXMLFile(plc_file)
- if result:
- return result
- else:
- self.CreateNewProject({"companyName": "",
- "productName": "",
- "productVersion": "",
- "projectName": "",
- "pageSize": (0, 0),
- "scaling": {}})
- if len(self.GetProjectConfigNames()) == 0:
- self.AddProjectDefaultConfiguration()
-
- # Change XSD into class members
- self._AddParamsMembers()
- self.Children = {}
-
- # Keep track of the root confnode (i.e. project path)
- self.ProjectPath = ProjectPath
-
- self.BuildPath = self._getBuildPath()
- if self.OrigBuildPath is not None:
- mycopytree(self.OrigBuildPath, self.BuildPath)
-
- # If dir have already be made, and file exist
- if os.path.isdir(self.CTNPath()) and os.path.isfile(self.ConfNodeXmlFilePath()):
- # Load the confnode.xml file into parameters members
- result = self.LoadXMLParams()
- if result:
- return result
- # Load and init all the children
- self.LoadChildren()
-
- canopen_child = self.GetChildByName("CanOpen")
- if havecanfestival and canopen_child is None:
- canopen = self.CTNAddChild("CanOpen", "CanOpen", 0)
- canopen.LoadChildren()
- canopen.CTNRequestSave()
-
- elif not havecanfestival and canopen_child is not None:
- canopen_child.CTNRemove()
-
- if self.CTNTestModified():
- self.SaveProject()
-
- if wx.GetApp() is None:
- self.RefreshConfNodesBlockLists()
- else:
- wx.CallAfter(self.RefreshConfNodesBlockLists)
-
- if arch in PLC_module:
- self.SetParamsAttribute('BeremizRoot.TargetType', 'MC9')
-
- return None
-
- def IsPLCStarted(self):
- return self.previous_plcstate == "Started" or self.previous_mode == SIMULATION_MODE
-
- def ShowMethod(self, name, val):
- simulating = self.CurrentMode == SIMULATION_MODE
- if type(val) == str:
- if val.endswith("simulating"):
- if val.startswith("not"):
- val = not simulating
- else:
- val = simulating
-
- ProjectController.ShowMethod(self, name, val)
-
- def UpdateMethodsFromPLCStatus(self):
- simulating = self.CurrentMode == SIMULATION_MODE
- if self.OnlineMode == "OFF":
- if simulating:
- status, log_count = self._connector.GetPLCstatus()
- self.UpdatePLCLog(log_count)
- status = "Disconnected"
- elif self.OnlineMode == "BOOTLOADER":
- status = "Connected"
+ if len(args) != 4 :
+ self.Usage()
+ sys.exit()
else:
- if self._connector is not None:
- status, log_count = self._connector.GetPLCstatus()
- if status == "Disconnected":
- self._SetConnector(None, False)
- else:
- self.UpdatePLCLog(log_count)
- else:
- status = "Disconnected"
- if self.previous_plcstate != status or self.previous_mode != self.CurrentMode:
- for args in _MethodFromPLCState.get(status, []):
- self.ShowMethod(*args)
- self.previous_plcstate = status
- self.previous_mode = self.CurrentMode
- if self.AppFrame is not None:
- self.AppFrame.RefreshStatusToolBar()
- connection_text = _("Connected to: ")
- status_text = ""
- if simulating:
- connection_text += _("Simulation")
- status_text += _("ON")
- if status == "Disconnected":
- if not simulating:
- self.AppFrame.ConnectionStatusBar.SetStatusText(_(status), 1)
- self.AppFrame.ConnectionStatusBar.SetStatusText('', 2)
- else:
- self.AppFrame.ConnectionStatusBar.SetStatusText(connection_text, 1)
- self.AppFrame.ConnectionStatusBar.SetStatusText(status_text, 2)
- else:
- if simulating:
- connection_text += " (%s)"
- status_text += " (%s)"
- else:
- connection_text += "%s"
- status_text += "%s"
- self.AppFrame.ConnectionStatusBar.SetStatusText(connection_text % self.ConnectorPath, 1)
- self.AppFrame.ConnectionStatusBar.SetStatusText(status_text % _(status), 2)
- return True
- return False
-
- def Generate_plc_declare_locations(self):
- """
- Declare used locations in order to simulatePLC in a black box
- """
- return """#include "iec_types_all.h"
-
-#define __LOCATED_VAR(type, name, ...) \
-type beremiz_##name;\
-type *name = &beremiz_##name;
-
-#include "LOCATED_VARIABLES.h"
-
-#undef __LOCATED_VAR
-
-"""
-
- def Generate_lpc_retain_array_sim(self):
- """
- Support for retain array in Simulation
- """
- return """/* Support for retain array */
-#define USER_RETAIN_ARRAY_SIZE 2000
-#define NUM_OF_COLS 3
-unsigned char readOK = 0;
-unsigned int foundIndex = USER_RETAIN_ARRAY_SIZE;
-unsigned int retainArray[USER_RETAIN_ARRAY_SIZE][NUM_OF_COLS];
-
-unsigned int __GetRetainData(unsigned char READ, unsigned int INDEX, unsigned int COLUMN)
-{
- if(READ == 1)
- {
- if((0<=INDEX) && (INDEX<USER_RETAIN_ARRAY_SIZE) && (0<=COLUMN) && (COLUMN<NUM_OF_COLS))
- {
- readOK = 1;
- return retainArray[INDEX][COLUMN];
- }
- }
-
- readOK = 0;
- return 0;
-}
-
-unsigned char __SetRetainData(unsigned char WRITE, unsigned int INDEX, unsigned int WORD1, unsigned int WORD2, unsigned int WORD3)
-{
- if(WRITE == 1)
- {
- if((0<=INDEX) && (INDEX<USER_RETAIN_ARRAY_SIZE))
- {
- retainArray[INDEX][0] = WORD1;
- retainArray[INDEX][1] = WORD2;
- retainArray[INDEX][2] = WORD3;
- return 1;
- }
- }
-
- return 0;
-}
-
-unsigned char __FindRetainData(unsigned char SEARCH, unsigned int START_IDX, unsigned int END_IDX, unsigned int WORD1, unsigned int WORD2, unsigned int WORD3)
-{
- unsigned int i;
-
- if((SEARCH==1) && (0<=START_IDX) && (START_IDX<USER_RETAIN_ARRAY_SIZE) && (START_IDX<=END_IDX) && (END_IDX<USER_RETAIN_ARRAY_SIZE))
- {
- for(i=START_IDX;i<=END_IDX;i++)
- {
- if((retainArray[i][0] == WORD1) && (retainArray[i][1] == WORD2) && (retainArray[i][2] == WORD3))
- {
- foundIndex = i;
- return 1;
- }
- }
- }
-
- foundIndex = USER_RETAIN_ARRAY_SIZE; /* Data not found => return index that is out of array bounds */
- return 0;
-}
-
-/* Since Beremiz debugger doesn't like pointer-by-reference stuff or global varibles, separate function is a must */
-unsigned char __GetReadStatus(unsigned char dummy)
-{
- return readOK;
-}
-
-unsigned int __GetFoundIndex(unsigned char dummy)
-{
- return foundIndex;
-}
-"""
-
- def _Simulate(self):
- """
- Method called by user to Simulate PLC
- """
- uri = "LOCAL://"
- try:
- self._SetConnector(connectors.ConnectorFactory(uri, self))
- except Exception, msg:
- self.logger.write_error(_("Exception while connecting %s!\n") % uri)
- self.logger.write_error(traceback.format_exc())
-
- # Did connection success ?
- if self._connector is None:
- # Oups.
- self.logger.write_error(_("Connection failed to %s!\n") % uri)
- self.StopSimulation()
- return False
-
- self.CurrentMode = SIMULATION_MODE
-
- buildpath = self._getBuildPath()
-
- # Eventually create build dir
- if not os.path.exists(buildpath):
- os.makedirs(buildpath)
-
- # Generate SoftPLC IEC code
- IECGenRes = self._Generate_SoftPLC()
+ self.projectOpen = args[0]
+ self.buildpath = args[1]
+ try:
+ self.port = int(args[2])
+ except:
+ self.Usage()
+ sys.exit()
+ self.arch = args[3]
+ SetLPCArch(self.arch)
- # If IEC code gen fail, bail out.
- if not IECGenRes:
- self.logger.write_error(_("IEC-61131-3 code generation failed !\n"))
- self.StopSimulation()
- return False
-
- # Reset variable and program list that are parsed from
- # CSV file generated by IEC2C compiler.
- self.ResetIECProgramsAndVariables()
-
- gen_result = self.CTNGenerate_C(buildpath, self.PLCGeneratedLocatedVars)
- CTNCFilesAndCFLAGS, CTNLDFLAGS, DoCalls = gen_result[:3]
- # if some files have been generated put them in the list with their location
- if CTNCFilesAndCFLAGS:
- self.LocationCFilesAndCFLAGS = [(self.GetCurrentLocation(), CTNCFilesAndCFLAGS, DoCalls)]
- else:
- self.LocationCFilesAndCFLAGS = []
-
- # confnode asks for some LDFLAGS
- if CTNLDFLAGS:
- # LDFLAGS can be either string
- if type(CTNLDFLAGS) == type(str()):
- self.LDFLAGS = [CTNLDFLAGS]
- # or list of strings
- elif type(CTNLDFLAGS) == type(list()):
- self.LDFLAGS = CTNLDFLAGS[:]
- else:
- self.LDFLAGS = []
-
- # Header file for extensions
- open(os.path.join(buildpath, "beremiz.h"), "w").write(targets.GetHeader())
-
- # Template based part of C code generation
- # files are stacked at the beginning, as files of confnode tree root
- for generator, filename, name in [
- # debugger code
- (self.Generate_plc_debugger, "plc_debugger.c", "Debugger"),
- # init/cleanup/retrieve/publish, run and align code
- (self.Generate_plc_main, "plc_main.c", "Common runtime"),
- # declare located variables for simulate in a black box
- (self.Generate_plc_declare_locations, "plc_declare_locations.c", "Declare Locations"),
- # declare located variables for simulate in a black box
- (self.Generate_lpc_retain_array_sim, "lpc_retain_array_sim.c", "Retain Array for Simulation")]:
- try:
- # Do generate
- code = generator()
- if code is None:
- raise
- code_path = os.path.join(buildpath, filename)
- open(code_path, "w").write(code)
- # Insert this file as first file to be compiled at root confnode
- self.LocationCFilesAndCFLAGS[0][1].insert(0, (code_path, self.plcCFLAGS))
- except Exception, exc:
- self.logger.write_error(name + _(" generation failed !\n"))
- self.logger.write_error(traceback.format_exc())
- self.StopSimulation()
- return False
-
- # Get simulation builder
- builder = self.GetBuilder()
- if builder is None:
- self.logger.write_error(_("Fatal : cannot get builder.\n"))
- self.StopSimulation()
- return False
-
- # Build
- try:
- if not builder.build():
- self.logger.write_error(_("C Build failed.\n"))
- self.StopSimulation()
- return False
- except Exception, exc:
- self.logger.write_error(_("C Build crashed !\n"))
- self.logger.write_error(traceback.format_exc())
- self.StopSimulation()
- return False
-
- data = builder.GetBinaryCode()
- if data is not None:
- if self._connector.NewPLC(builder.GetBinaryCodeMD5(), data, []):
- self.UnsubscribeAllDebugIECVariable()
- self.ProgramTransferred()
- if self.AppFrame is not None:
- self.AppFrame.CloseObsoleteDebugTabs()
- self.AppFrame.RefreshPouInstanceVariablesPanel()
- self.logger.write(_("Transfer completed successfully.\n"))
- else:
- self.logger.write_error(_("Transfer failed\n"))
- self.StopSimulation()
- return False
-
- self._Run()
-
- if not self.StatusTimer.IsRunning():
- # Start the status Timer
- self.StatusTimer.Start(milliseconds=500, oneShot=False)
-
- def StopSimulation(self):
- self.CurrentMode = None
- self._SetConnector(None, False)
- self.ApplyOnlineMode()
-
- def _Stop(self):
- ProjectController._Stop(self)
-
- if self.CurrentMode == SIMULATION_MODE:
- self.StopSimulation()
-
- def CompareLocalAndRemotePLC(self):
- # if self.LPCConnector is None:
- # return
- if self._connector is None:
- return
- # We are now connected. Update button status
- MD5 = self.GetLastBuildMD5()
- # Check remote target PLC correspondance to that md5
- # if MD5 is not None and self.LPCConnector.MatchMD5(MD5):
- if MD5 is not None and self._connector.MatchMD5(MD5):
- # warns controller that program match
- self.ProgramTransferred()
-
- def ResetBuildMD5(self):
- builder = self.GetBuilder()
- if builder is not None:
- builder.ResetBinaryCodeMD5(*([] if arch in PLC_module else [self.OnlineMode]))
-
- def GetLastBuildMD5(self):
- builder = self.GetBuilder()
- if builder is not None:
- return builder.GetBinaryCodeMD5(*([] if arch in PLC_module else [self.OnlineMode]))
- else:
- return None
-
- def _Clean(self, building = False):
- self._CloseView(self._IECCodeView)
- runtime_list = fnmatch.filter(os.listdir(self._getBuildPath()), 'runtime_*')
- if os.path.isdir(os.path.join(self._getBuildPath())) and os.path.isfile(
- os.path.join(self._getBuildPath(), "hmi.py")) or runtime_list != []:
- self.logger.write(_("Cleaning the build directory\n"))
- # self.logger.write(_(str(os.path.join(self._getBuildPath(), "hmi.py"))))
- for file in runtime_list:
- os.remove(os.path.join(self._getBuildPath(), file))
- if os.path.isfile(os.path.join(self._getBuildPath(), "hmi.py")):
- os.remove(os.path.join(self._getBuildPath(), "hmi.py"))
- else:
- if not building:
- self.logger.write_error(_("Build directory already clean\n"))
- self.ShowMethod("_showIECcode", False)
- self.EnableMethod("_Clean", False)
- # kill the builder
- self._builder = None
- self.CompareLocalAndRemotePLC()
+ # overload with exacltly same code, but this is intended.
+ # we want extensions to use globals of this module, not Beremiz.py
+ def globals(self):
+ return globals()
- def _Transfer(self):
- if self.OnlineMode == "NORMAL":
- if self.IsPLCStarted():
- dialog = wx.MessageDialog(self.AppFrame, "You must stop the PLC before transfer. Do you want to stop it now and transfer?", style=wx.YES_NO|wx.CENTRE)
- if dialog.ShowModal() == wx.ID_YES:
- self._Stop()
- else:
- return
- ProjectController._Transfer(self)
- return
- if self.CurrentMode is None and self.OnlineMode != "OFF":
- self.CurrentMode = TRANSFER_MODE
-
- if ProjectController._Build(self):
-
- ID_ABORTTRANSFERTIMER = wx.NewId()
- self.AbortTransferTimer = wx.Timer(self.AppFrame, ID_ABORTTRANSFERTIMER)
- self.AppFrame.Bind(wx.EVT_TIMER, self.AbortTransfer, self.AbortTransferTimer)
-
- if self.OnlineMode == "BOOTLOADER":
- self.BeginTransfer()
-
- else:
- self.logger.write(_("Resetting PLC\n"))
- # self.StatusTimer.Stop()
- self.LPCConnector.ResetPLC()
- self.AbortTransferTimer.Start(milliseconds=5000, oneShot=True)
-
- else:
- self.CurrentMode = None
-
- def BeginTransfer(self):
- self.logger.write(_("Start PLC transfer\n"))
-
- self.AbortTransferTimer.Stop()
- ProjectController._Transfer(self)
- self.AbortTransferTimer.Start(milliseconds=5000, oneShot=True)
-
- def AbortTransfer(self, event):
- self.logger.write_warning(_("Timeout waiting PLC to recover\n"))
-
- self.CurrentMode = None
- self.AbortTransferTimer.Stop()
- self.AbortTransferTimer = None
- event.Skip()
-
- old_DebugThreadProc = ProjectController.DebugThreadProc
- def LPCManager_DebugThreadProc(self, checking=False):
- if checking:
- state, ls = self._connector.GetTraceVariables()
- while state == "Stopped":
- state, ls = self._connector.GetTraceVariables()
- time.sleep(0.1)
-
- self.old_DebugThreadProc()
-
- def _connect_debug(self, checking = False):
- self.previous_plcstate = None
- if self.AppFrame:
- self.AppFrame.ResetGraphicViewers()
- self.RegisterDebugVarToConnector()
- if self.DispatchDebugValuesTimer is not None:
- self.DispatchDebugValuesTimer.Start(
- int(REFRESH_PERIOD * 1000), oneShot=True)
- if self.DebugThread is None:
- # self.DebugThread = Thread(target=self.DebugThreadProc)
- self.DebugThread = Thread(target=self.LPCManager_DebugThreadProc, args=(checking, ))
- self.DebugThread.setDaemon(True)
- self.DebugThread.start()
-
- def _Run(self):
- """
- Start PLC
- """
- if self.GetIECProgramsAndVariables():
- self._connector.StartPLC()
- self.logger.write(_("Starting PLC\n"))
- self._connect_debug(True)
- else:
- self.logger.write_error(_("Couldn't start PLC !\n"))
- self.UpdateMethodsFromPLCStatus()
-
- def _Disconnect(self):
- self._SetConnector(None)
- self.KillDebugThread()
-
- def _UpdateFw(self):
- """
- Method called by user to flash the firmware of the PLC
- """
- from FirmwareUpdateDialog import FirmwareUpdateDialog
- from dialogs import DiscoveryDialog
- from HostFirmwareUpdater import HostFirmwareUpdater
-
- if self.firmawreUpadateIsRunning == True:
- self.logger.write_error(_("Firmware update is already running!\n"))
- return
-
- self.firmawreUpadateIsRunning = True
- self.logger.write(_("Firmware update started\n"))
-
- # Launch the firmware selection dialog
- dialog = FirmwareUpdateDialog(self.AppFrame)
- answer = dialog.ShowModal()
- imageFilePath = dialog.GetFirmwareImageFile()
- updateType = dialog.GetFirmwareUpdateType()
- chunksSize = dialog.GetChunksSize()
- reboot = dialog.GetReboot()
- dialog.Destroy()
-
- if answer == wx.ID_CANCEL:
- self.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- return
-
- if imageFilePath == None or imageFilePath == "":
- self.logger.write_error(_("No firmware image file selected!\n"))
- self.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- return
- else:
- self.logger.write(_("Firmware image file: %s\n") % imageFilePath)
-
- if updateType == 1:
- self.logger.write(_("Firmware update type: Linux kernel image\n"))
- elif updateType == 2:
- self.logger.write(_("Firmware update type: Linux DTB image\n"))
- elif updateType == 3:
- self.logger.write(_("Firmware update type: Root file system image\n"))
- else:
- self.logger.write_error(_("Unknown firmware update type!\n"))
- self.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- return
-
- if chunksSize < 1024 or chunksSize > 1024 * 1024:
- self.logger.write_error(_("Bad chunks size : %d KiB!\n") % chunksSize)
- self.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- return
- else:
- self.logger.write(_("Chunks size : %d KiB\n") % chunksSize)
-
- self.logger.write(_("Reboot after update : %s\n") % ("Yes" if reboot else "No"))
- # Get the target PLC URI
- # Check if an uri is already configured in the Beremiz project
- uri = self.BeremizRoot.getURI_location()
- if uri is not None and uri != "":
- self.logger.write(_("PLC URI configured in the Beremiz project will be used: %s\n") % uri)
- else:
- # PLC URI is not configured in the Beremiz project
- # Launch Service Discovery dialog
- self.logger.write(_("PLC URI is not configured in the Beremiz project. Launching the Discover dialog\n"))
- dialog = DiscoveryDialog(self.AppFrame)
- answer = dialog.ShowModal()
- uri = dialog.GetURI()
- dialog.Destroy()
-
- # Nothing choosed or cancel button
- if uri is None or answer == wx.ID_CANCEL:
- self.logger.write_error(_("Connection canceled!\n"))
- self.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- return
+ def CreateUI(self):
+ CMDpipe = self.StdoutPseudoFile.StdoutPseudoFile(self.port, self.debug)
- # Get connector from uri
- self._connector = None
- try:
- self._SetConnector(connectors.ConnectorFactory(uri, self))
- except Exception:
- self.logger.write_error(_("Exception while connecting %s!\n") % uri)
- self.logger.write_error(traceback.format_exc())
- self.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- return
-
- # Did connection success ?
- if self._connector is None:
- # Oups.
- self.logger.write_error(_("Connection failed to %s!\n") % uri)
- self.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- return
- else:
- self.logger.write(_("Connected.\n"))
-
- # Last confirmation before firmware update
- answer = wx.MessageBox(_('Are you sure to launch the firmware update for the selected PLC?'),
- _('Firmware Update'), wx.YES_NO | wx.CENTRE | wx.NO_DEFAULT,
- self.AppFrame)
- if answer != wx.YES:
- self.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- return
- # Some cosmetics
- self.AppFrame.Refresh()
- self.AppFrame.Update()
-
- # Lauch the firmaware update on the remote PLC
- updater = HostFirmwareUpdater(self._connector, imageFilePath, updateType, chunksSize, reboot, self.logger)
- try:
- updater.update()
- except Exception as e:
- self.logger.write_error(str(e) + "\n")
- self.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- self._Disconnect()
- return
- self._Disconnect()
- self.firmawreUpadateIsRunning = False
- return True
-
-
-# -------------------------------------------------------------------------------
-# LPCBeremiz Class
-# -------------------------------------------------------------------------------
-lpcberemiz_cmd = None
-
-
-class LPCBeremiz(Beremiz):
- def _init_coll_FileMenu_Items(self, parent):
- config = wx.ConfigBase.Get()
- export = str(config.Read("Exporter"))
- if export == "":
- config.Write("Exporter", '0')
- export = '0'
- if export == '1':
- export = True
- else:
- export = False
- AppendMenu(parent, help='', id=wx.ID_SAVE,
- kind=wx.ITEM_NORMAL, text=_(u'Save\tCTRL+S'))
- AppendMenu(parent, help='', id=wx.ID_CLOSE,
- kind=wx.ITEM_NORMAL, text=_(u'Close Tab\tCTRL+W'))
- parent.AppendSeparator()
- AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP,
- kind=wx.ITEM_NORMAL, text=_(u'Page Setup'))
- AppendMenu(parent, help='', id=wx.ID_PREVIEW,
- kind=wx.ITEM_NORMAL, text=_(u'Preview'))
- AppendMenu(parent, help='', id=wx.ID_PRINT,
- kind=wx.ITEM_NORMAL, text=_(u'Print'))
- parent.AppendSeparator()
- if export:
- AppendMenu(parent, help='', id=ID_EXPORT,
- kind=wx.ITEM_NORMAL, text=_(u'Export'))
- parent.AppendSeparator()
- AppendMenu(parent, help='', id=wx.ID_EXIT,
- kind=wx.ITEM_NORMAL, text=_(u'Quit\tCTRL+Q'))
-
- self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE)
- self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE)
- self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP)
- self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW)
- self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT)
- if export:
- self.Bind(wx.EVT_MENU, lambda event: VariableWriter(self, event, self.CTR.ProjectPath), id=ID_EXPORT)
- self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT)
-
- self.AddToMenuToolBar([(wx.ID_SAVE, "save", _(u'Save'), None),
- (wx.ID_PRINT, "print", _(u'Print'), None)])
-
-
-
- def _init_ctrls(self, prnt):
- Beremiz._init_ctrls(self, prnt)
-
- def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True):
- self.ConfNodeInfos = {}
-
- Beremiz.__init__(self, parent, projectOpen, buildpath, ctr, debug)
-
- def Show(self, loading=True):
- wx.Frame.Show(self)
- # WTF, really ?
- # if loading:
- # loading_splash = splash.SmartehScreenSplash(self, bitmap=GetPath(splash.SPLASH_FN), signal=signal_init)
- # thread = Thread(target=loading_splash.Show)
- # thread.start()
- # #thread.join()
-
- def OnCloseFrame(self, event):
- global frame
-
- if self.CheckSaveBeforeClosing(_("Close Application")):
-
- frame.Hide()
-
- self.CTR.ResetAppFrame(lpcberemiz_cmd.Log)
- if self.CTR.OnlineMode == 0:
- self.CTR._SetConnector(None, False)
-
- self.CTR.KillDebugThread()
- self.KillLocalRuntime()
-
- # close wxGlade if running
- config = wx.ConfigBase.Get()
- wxGladePid = str(config.Read("BeremizRoot.wxGlade"))
- if wxGladePid != '0':
- import signal
- os.kill(int(wxGladePid), signal.SIGTERM)
- wxGladePid = 0
- config.Write("BeremizRoot.wxGlade", str(wxGladePid))
- config.Flush()
-
- self.SaveLastState()
-
- lpcberemiz_cmd.Log.write("Closed\n")
-
- event.Veto()
-
- def RefreshTitle(self):
- name = _("Beremiz")
- if self.CTR is not None:
- projectname = self.CTR.GetProjectName()
- if self.CTR.ProjectTestModified():
- projectname = "~%s~" % projectname
- self.SetTitle("%s - %s" % (name, projectname))
- else:
- self.SetTitle(name)
+ if self.projectOpen is not None:
+ self.projectOpen = self.BeremizIDE.DecodeFileSystemPath(self.projectOpen, False)
- def RefreshFileMenu(self):
- MenuToolBar = self.Panes["MenuToolBar"]
- if self.CTR is not None:
- selected = self.TabsOpened.GetSelection()
- if selected >= 0:
- graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer)
- else:
- graphic_viewer = False
- if self.TabsOpened.GetPageCount() > 0:
- self.FileMenu.Enable(wx.ID_CLOSE, True)
- if graphic_viewer:
- self.FileMenu.Enable(wx.ID_PREVIEW, True)
- self.FileMenu.Enable(wx.ID_PRINT, True)
- MenuToolBar.EnableTool(wx.ID_PRINT, True)
- else:
- self.FileMenu.Enable(wx.ID_PREVIEW, False)
- self.FileMenu.Enable(wx.ID_PRINT, False)
- MenuToolBar.EnableTool(wx.ID_PRINT, False)
- else:
- self.FileMenu.Enable(wx.ID_CLOSE, False)
- self.FileMenu.Enable(wx.ID_PREVIEW, False)
- self.FileMenu.Enable(wx.ID_PRINT, False)
- MenuToolBar.EnableTool(wx.ID_PRINT, False)
- self.FileMenu.Enable(wx.ID_PAGE_SETUP, True)
- project_modified = self.CTR.ProjectTestModified()
- self.FileMenu.Enable(wx.ID_SAVE, project_modified)
- MenuToolBar.EnableTool(wx.ID_SAVE, project_modified)
+ CTR = self.LPCProjectController.LPCProjectController(
+ None, CMDpipe, self.buildpath, self.arch)
+ if self.projectOpen is not None and os.path.isdir(self.projectOpen):
+ result = CTR.LoadProject(self.projectOpen)
+ if result:
+ CMDpipe.write("Error: Invalid project directory", result)
else:
- self.FileMenu.Enable(wx.ID_CLOSE, False)
- self.FileMenu.Enable(wx.ID_PAGE_SETUP, False)
- self.FileMenu.Enable(wx.ID_PREVIEW, False)
- self.FileMenu.Enable(wx.ID_PRINT, False)
- MenuToolBar.EnableTool(wx.ID_PRINT, False)
- self.FileMenu.Enable(wx.ID_SAVE, False)
- MenuToolBar.EnableTool(wx.ID_SAVE, False)
-
- def RefreshScrollBars(self):
- xstart, ystart = self.PLCConfig.GetViewStart()
- window_size = self.PLCConfig.GetClientSize()
- sizer = self.PLCConfig.GetSizer()
- if sizer:
- maxx, maxy = sizer.GetMinSize()
- posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
- posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
- self.PLCConfig.Scroll(posx, posy)
- self.PLCConfig.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
- maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
-
- def RefreshAll(self):
- Beremiz.RefreshAll(self)
-
- # Remove taskbar icon when simulating
- def StartLocalRuntime(self, taskbaricon=True):
- return Beremiz.StartLocalRuntime(self, taskbaricon=False)
-
-
-class StdoutPseudoFile:
- def __init__(self, port):
- self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.socket.connect(('localhost', port))
- self.Buffer = ""
-
- def __del__(self):
- self.socket.close()
-
- def readline(self):
- idx = self.Buffer.find("\n")
- while idx == -1:
- text = self.socket.recv(2048)
- if text == "":
- return ""
- self.Buffer += text
- idx = self.Buffer.find("\n")
- if idx != -1:
- line = self.Buffer[:idx + 1]
- self.Buffer = self.Buffer[idx + 1:]
- if BMZ_DBG:
- print "command >" + line
- return line
- return ""
-
- """ Base class for file like objects to facilitate StdOut for the Shell."""
-
- def write(self, s, style=None):
- if s != '':
- self.socket.send(s.encode('utf8'))
-
- def writeyield(self, s):
- self.write(s)
-
- def write_warning(self, s):
- self.write(s)
-
- def write_error(self, s):
- self.write(s)
-
- def flush(self):
- pass
-
- def isatty(self):
- return False
-
-
-from threading import Thread, Timer, Semaphore, Lock
-import cmd
-
-build_lock = Lock()
-wx_eval_lock = Semaphore(0)
-eval_res = None
-
-
-def wx_evaluator(callable, *args, **kwargs):
- global eval_res
- eval_res = None
- try:
- eval_res = callable(*args, **kwargs)
- finally:
- wx_eval_lock.release()
-
-
-def evaluator(callable, *args, **kwargs):
- global eval_res
- wx.CallAfter(wx_evaluator, callable, *args, **kwargs)
- wx_eval_lock.acquire()
- return eval_res
-
-
-# Command log for debug, for viewing from wxInspector
-if BMZ_DBG:
- __builtins__.cmdlog = []
-
-
-class LPCBeremiz_Cmd(cmd.Cmd):
-
- prompt = ""
- RefreshTimer = None
-
- def __init__(self, CTR, Log):
- cmd.Cmd.__init__(self, stdin=Log, stdout=Log)
- self.use_rawinput = False
- self.restore_last_state = False
- self.Log = Log
- self.CTR = CTR
-
- def RestartTimer(self):
- if self.RefreshTimer is not None:
- self.RefreshTimer.cancel()
- self.RefreshTimer = Timer(0.1, wx.CallAfter, args=[self.Refresh])
- self.RefreshTimer.start()
-
- def Exit(self):
- global frame, app
- self.Close()
- app.ExitMainLoop()
- return True
-
- def do_EOF(self, line):
- return self.Exit()
+ CMDpipe.write("Error: No such file or directory")
- def Show(self, loading=False):
- global frame
- if frame is not None:
- self.CTR.SetAppFrame(frame, frame.Log)
- self.CTR.UpdateMethodsFromPLCStatus()
- frame.Show(loading)
- frame.Raise()
- self.restore_last_state = True
- #self.RestartTimer()
-
- def Refresh(self):
- global frame
- if frame is not None:
- if self.restore_last_state:
- self.restore_last_state = False
- frame.RestoreLastState()
- else:
- frame.RefreshEditor()
- frame._Refresh(TITLE, PROJECTTREE, POUINSTANCEVARIABLESPANEL, FILEMENU, EDITMENU)
- frame.RefreshAll()
-
- def Close(self):
- global frame
-
- self.CTR.ResetAppFrame(self.Log)
- if frame is not None:
- frame.Hide()
-
- def Compile(self):
- self.CTR._Build()
-
- def SetProjectProperties(self, projectname, productname, productversion, companyname):
- new_properties = {
- "projectName": projectname,
- "productName": productname,
- "productVersion": productversion,
- "companyName": companyname}
- self.CTR.SetProjectProperties(properties=new_properties, buffer=False)
- self.RestartTimer()
-
- def SetOnlineMode(self, mode, path=None):
- self.CTR.SetOnlineMode(mode, path)
- self.RestartTimer()
-
- def AddBus(self, iec_channel, name, icon=None):
- for child in self.CTR.IterChildren():
- if child.BaseParams.getName() == name:
- return "Error: A bus named %s already exists\n" % name
- elif child.BaseParams.getIEC_Channel() == iec_channel:
- return "Error: A bus with IEC_channel %d already exists\n" % iec_channel
- bus = self.CTR.CTNAddChild(name, "LPCBus", iec_channel)
- if bus is None:
- return "Error: Unable to create bus\n"
- bus.SetIcon(icon)
- self.RestartTimer()
-
- def RenameBus(self, iec_channel, name):
- bus = self.CTR.GetChildByIECLocation((iec_channel,))
- if bus is None:
- return "Error: No bus found\n"
- for child in self.CTR.IterChildren():
- if child != bus and child.BaseParams.getName() == name:
- return "Error: A bus named %s already exists\n" % name
- bus.BaseParams.setName(name)
- self.RestartTimer()
+ lpcberemiz_cmd = self.LPCCommand.LPCCommand(self, CTR, CMDpipe)
- def ChangeBusIECChannel(self, old_iec_channel, new_iec_channel):
- bus = self.CTR.GetChildByIECLocation((old_iec_channel,))
- if bus is None:
- return "Error: No bus found\n"
- for child in self.CTR.IterChildren():
- if child != bus and child.BaseParams.getIEC_Channel() == new_iec_channel:
- return "Error: A bus with IEC_channel %d already exists\n" % new_iec_channel
- if wx.GetApp() is None:
- self.CTR.UpdateProjectVariableLocation(str(old_iec_channel),
- str(new_iec_channel))
- else:
- self.CTR.UpdateProjectVariableLocation(
- str(old_iec_channel),
- str(new_iec_channel))
- bus.BaseParams.setIEC_Channel(new_iec_channel)
- self.RestartTimer()
-
- def RemoveBus(self, iec_channel):
- bus = self.CTR.GetChildByIECLocation((iec_channel,))
- if bus is None:
- return "Error: No bus found\n"
- self.CTR.RemoveProjectVariableByFilter(str(iec_channel))
- self.CTR.Children["LPCBus"].remove(bus)
- self.RestartTimer()
-
- def AddModule(self, parent, iec_channel, name, icode, icon=None):
- module = self.CTR.GetChildByIECLocation(parent)
- if module is None:
- return "Error: No parent found\n"
- for child in GetModuleChildren(module):
- if child["name"] == name:
- return "Error: A module named %s already exists\n" % name
- elif child["IEC_Channel"] == iec_channel:
- return "Error: A module with IEC_channel %d already exists\n" % iec_channel
- GetLastModuleGroup(module).append({"name": name,
- "type": LOCATION_MODULE,
- "IEC_Channel": iec_channel,
- "icon": icon,
- "init": icode,
- "children": []})
- self.RestartTimer()
-
- def RenameModule(self, iec_location, name):
- module = self.CTR.GetChildByIECLocation(iec_location)
- if module is None:
- return "Error: No module found\n"
- parent = self.CTR.GetChildByIECLocation(iec_location[:-1])
- if parent is self.CTR:
- return "Error: No module found\n"
- if module["name"] != name:
- for child in GetModuleChildren(parent):
- if child["name"] == name:
- return "Error: A module named %s already exists\n" % name
- module["name"] = name
- self.RestartTimer()
-
- def ChangeModuleIECChannel(self, old_iec_location, new_iec_channel):
- module = self.CTR.GetChildByIECLocation(old_iec_location)
- if module is None:
- return "Error: No module found\n"
- parent = self.CTR.GetChildByIECLocation(old_iec_location[:-1])
- if parent is self.CTR:
- return "Error: No module found\n"
- if module["IEC_Channel"] != new_iec_channel:
- for child in GetModuleChildren(parent):
- if child["IEC_Channel"] == new_iec_channel:
- return "Error: A module with IEC_channel %d already exists\n" % new_iec_channel
- self.CTR.UpdateProjectVariableLocation(".".join(map(str, old_iec_location)),
- ".".join(map(str, old_iec_location[:1] + (new_iec_channel,))))
- module["IEC_Channel"] = new_iec_channel
- self.RestartTimer()
-
- def ChangeModuleInitCode(self, iec_location, icode):
- module = self.CTR.GetChildByIECLocation(iec_location)
- if module is None:
- return "Error: No module found\n"
- module["init"] = icode
-
- def RemoveModule(self, parent, iec_channel):
- module = self.CTR.GetChildByIECLocation(parent)
- if module is None:
- return "Error: No parent found\n"
- child = GetModuleBySomething(module, "IEC_Channel", (iec_channel,))
- if child is None:
- return "Error: No module found\n"
- self.CTR.RemoveProjectVariableByFilter(".".join(map(str, parent + (iec_channel,))))
- RemoveModuleChild(module, child)
- self.RestartTimer()
+ cmd_thread = Thread(target=lpcberemiz_cmd.cmdloop)
+ cmd_thread.start()
+ # TODO: join() when exiting
- def StartGroup(self, parent, name, icon=None):
- module = self.CTR.GetChildByIECLocation(parent)
- if module is None:
- return "Error: No parent found\n"
- for child in module["children"]:
- if child["type"] == LOCATION_GROUP and child["name"] == name:
- return "Error: A group named %s already exists\n" % name
- module["children"].append({"name": name,
- "type": LOCATION_GROUP,
- "icon": icon,
- "children": []})
- self.RestartTimer()
-
- def AddVariable(self, parent, location, name, direction, type, rcode, pcode, description=""):
- module = self.CTR.GetChildByIECLocation(parent)
- if module is None:
- return "Error: No parent found\n"
- for child in GetModuleChildren(module):
- if child["name"] == name:
- return "Error: A variable named %s already exists\n" % name
- if child["location"] == location and child["type"] == LOCATION_TYPES[direction]:
- return "Error: A variable with location %s already exists\n" % ".".join(map(str, location))
- GetLastModuleGroup(module).append({"name": name,
- "location": location,
- "type": LOCATION_TYPES[direction],
- "IEC_type": type,
- "description": description,
- "retrieve": rcode,
- "publish": pcode})
- self.RestartTimer()
-
- def ChangeVariableParams(self, parent, location, new_name, new_direction, new_type, new_rcode, new_pcode,
- new_description=None):
- module = self.CTR.GetChildByIECLocation(parent)
- if module is None:
- return "Error: No parent found\n"
- variable = None
- for child in GetModuleChildren(module):
- if child["location"] == location and child["type"] == LOCATION_TYPES[new_direction]:
- variable = child
- elif child["name"] == new_name:
- return "Error: A variable named %s already exists\n" % new_name
- if variable is None:
- return "Error: No variable found\n"
- if variable["name"] != new_name:
- self.CTR.UpdateProjectVariableName(variable["name"], new_name)
- variable["name"] = new_name
- variable["type"] = LOCATION_TYPES[new_direction]
- variable["IEC_type"] = new_type
- variable["retrieve"] = new_rcode
- variable["publish"] = new_pcode
- if new_description is not None:
- variable["description"] = new_description
- self.RestartTimer()
-
- def RemoveVariable(self, parent, location, direction):
- module = self.CTR.GetChildByIECLocation(parent)
- if module is None:
- return "Error: No parent found\n"
- child = GetModuleVariable(module, location, direction)
- if child is None:
- return "Error: No variable found\n"
- size = LOCATION_SIZES[self.CTR.GetBaseType(child["IEC_type"])]
- address = "%" + LOCATION_DIRS[child["type"]] + size + ".".join(map(str, parent + location))
- self.CTR.RemoveProjectVariableByAddress(address)
- RemoveModuleChild(module, child)
- self.RestartTimer()
-
-
-def location(loc):
- return tuple(map(int, loc.split(".")))
-
-
-def GetCmdFunction(function, arg_types, opt=0):
- arg_number = len(arg_types)
+ self.frame = self.LPCBeremiz.LPCBeremiz(None, ctr=CTR, pipe=CMDpipe)
- def CmdFunction(self, line):
- args_toks = line.split('"')
- if len(args_toks) % 2 == 0:
- self.Log.write("Error: Invalid command\n")
- sys.stdout.flush()
- return
- args = []
- for num, arg in enumerate(args_toks):
- if num % 2 == 0:
- stripped = arg.strip()
- if stripped:
- args.extend(stripped.split(" "))
- else:
- args.append(arg)
- number = None
- extra = ""
- if opt == 0 and len(args) != arg_number:
- number = arg_number
- elif len(args) > arg_number:
- number = arg_number
- extra = " at most"
- elif len(args) < arg_number - opt:
- number = arg_number - opt
- extra = " at least"
- if number is not None:
- if number == 0:
- self.Log.write("Error: No argument%s expected\n" % extra)
- elif number == 1:
- self.Log.write("Error: 1 argument%s expected\n" % extra)
- else:
- self.Log.write("Error: %d arguments%s expected\n" % (number, extra))
- sys.stdout.flush()
- return
- for num, arg in enumerate(args):
- try:
- args[num] = arg_types[num](arg)
- except:
- self.Log.write("Error: Invalid value for argument %d\n" % (num + 1))
- sys.stdout.flush()
- return
+ def CreateApplication(self):
+ # Create app usual way
+ BeremizIDELauncher.CreateApplication(self)
- func = getattr(self, function)
- res = evaluator(func, *args)
-
- if BMZ_DBG:
- cmdlog.append((function, line, res))
- if len(cmdlog) > 100: # prevent debug log to grow too much
- cmdlog.pop(0)
-
- if isinstance(res, (StringType, UnicodeType)):
- self.Log.write(res)
- return False
- else:
- return res
-
- return CmdFunction
-
-
-def CmdThreadProc(CTR, Log):
- global lpcberemiz_cmd
- for function, (arg_types, opt) in {"Exit": ([], 0),
- "Show": ([bool], 1),
- "Refresh": ([], 0),
- "Close": ([], 0),
- "Compile": ([], 0),
- "SetProjectProperties": ([str, str, str, str], 0),
- "SetOnlineMode": ([str, str], 1),
- "AddBus": ([int, str, str], 1),
- "RenameBus": ([int, str], 0),
- "ChangeBusIECChannel": ([int, int], 0),
- "RemoveBus": ([int], 0),
- "AddModule": ([location, int, str, str, str], 1),
- "RenameModule": ([location, str], 0),
- "ChangeModuleIECChannel": ([location, int], 0),
- "ChangeModuleInitCode": ([location, str], 0),
- "RemoveModule": ([location, int], 0),
- "StartGroup": ([location, str, str], 1),
- "AddVariable": ([location, location, str, str, str, str, str, str], 1),
- "ChangeVariableParams": (
- [location, location, str, str, str, str, str, str], 1),
- "RemoveVariable": ([location, location], 0)}.iteritems():
- setattr(LPCBeremiz_Cmd, "do_%s" % function, GetCmdFunction(function, arg_types, opt))
- lpcberemiz_cmd = LPCBeremiz_Cmd(CTR, Log)
- lpcberemiz_cmd.cmdloop()
+ # Add LPCmanager's image folder to searched ones.
+ AddBitmapFolder(os.path.join(_lpcmanager_path, "images"))
if __name__ == '__main__':
- Log = StdoutPseudoFile(port)
-
- if projectOpen is not None:
- projectOpen = DecodeFileSystemPath(projectOpen, False)
-
- CTR = LPCProjectController(None, Log, buildpath)
- if projectOpen is not None and os.path.isdir(projectOpen):
- result = CTR.LoadProject(projectOpen)
- if result:
- Log.write("Error: Invalid project directory", result)
- else:
- Log.write("Error: No such file or directory")
-
- cmd_thread = Thread(target=CmdThreadProc, args=[CTR, Log])
- cmd_thread.start()
-
- # Install a exception handle for bug reports
- import util.ExceptionHandler
- util.ExceptionHandler.AddExceptHook(version.app_version)
-
- frame = LPCBeremiz(None, ctr=CTR, debug=True)
-
- app.MainLoop()
+ lpcmanager = LPCManagerLauncher()
+ lpcmanager.Start()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LPCProjectController.py Wed Apr 11 13:06:58 2018 +0200
@@ -0,0 +1,268 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+import os
+import zipfile
+import wx
+
+from ProjectController import ProjectController
+from LPCArch import PLC_module
+
+from FirmwareUpdateDialog import FirmwareUpdateDialog
+from dialogs import DiscoveryDialog
+from HostFirmwareUpdater import HostFirmwareUpdater
+
+
+LPCStatusMethods = [
+ {"bitmap": "UpdateFw",
+ "name": _("UpdateFw"),
+ "shown": True,
+ "tooltip": _("Update the PLC firmware"),
+ "method": "_UpdateFw"}
+]
+
+
+class LPCProjectController(ProjectController):
+ StatusMethods = ProjectController.StatusMethods + LPCStatusMethods
+
+ def __init__(self, frame, logger, buildpath, arch):
+ self.arch = arch
+ self.OrigBuildPath = buildpath
+
+ ProjectController.__init__(self, frame, logger)
+
+ # Firmware update running status
+ self.firmwareUpadateIsRunning = False
+
+ def GetProjectName(self):
+ """
+ Beremiz uses project directory name as project name
+ In LPCManager, project name is given as PLCOpen project name
+ and is passed at startup by SetProjectProperties command
+ """
+ return self.Project.getname()
+
+ def xEyeExport(self):
+ """
+ Zip project files for use in xEye
+ """
+ opj = os.path.join
+ ops = os.path.split
+ output_file_path = opj(ops(self._getBuildPath())[0],
+ self.GetProjectName() + ".xEye")
+
+ zf = zipfile.ZipFile(output_file_path, mode='w',
+ compression=zipfile.ZIP_DEFLATED)
+
+ for extrafilespath in [self._getExtraFilesPath(),
+ self._getProjectFilesPath()]:
+ dirname = ops(extrafilespath)[-1]
+ for name in os.listdir(extrafilespath):
+ zf.write(opj(extrafilespath, str(name)), opj(dirname, str(name)), zipfile.ZIP_DEFLATED)
+ zf.write(self._builder.exe_path, self._builder.exe)
+ zf.write(opj(self._getBuildPath(), 'lastbuildPLC.md5'), 'lastbuildPLC.md5')
+ zf.close()
+ self.logger.write(_("xEye export file created at: %s\n") % output_file_path)
+
+ def _Build(self):
+ """
+ AutoSave before regular build, and zip for xEye after
+ """
+ if self.ProjectTestModified():
+ self.SaveProject()
+ self.AppFrame.RefreshAfterSave()
+
+ result = ProjectController._Build(self)
+
+ if result:
+ self.xEyeExport()
+ return result
+
+ def SetProjectName(self, name):
+ return self.Project.setname(name)
+
+ def SetOnlineMode(self, mode, path=None):
+ # SetOnlineMode is only for MC8
+ return None
+
+ # Update a PLCOpenEditor Pou variable location
+ def UpdateProjectVariableLocation(self, old_leading, new_leading):
+ self.Project.updateElementAddress(old_leading, new_leading)
+ self.BufferProject()
+
+ # Update a PLCOpenEditor Pou variable name
+ def UpdateProjectVariableName(self, old_name, new_name):
+ self.Project.updateElementName(old_name, new_name)
+ self.BufferProject()
+
+ def RemoveProjectVariableByAddress(self, address):
+ self.Project.removeVariableByAddress(address)
+ self.BufferProject()
+
+ def RemoveProjectVariableByFilter(self, leading):
+ self.Project.removeVariableByFilter(leading)
+ self.BufferProject()
+
+ def AddProjectDefaultConfiguration(self, config_name="config", res_name="resource1"):
+ ProjectController.AddProjectDefaultConfiguration(self, config_name, res_name)
+
+ self.SetEditedResourceInfos(
+ self.ComputeConfigurationResourceName(config_name, res_name),
+ [{"Name": "main_task",
+ "Triggering": "Cyclic",
+ "Interval": "T#50ms",
+ "Priority": 0}],
+ [])
+
+ def LoadProject(self, ProjectPath, BuildPath=None):
+ """
+ Create plcopen project if plc.xml not found,
+ so that original LoadProject doesn't make errors.
+ After regular load, add CanOpen nodes if not already there,
+ and eventualy save project again.
+ TargetType is forced to MC9.
+ """
+ plc_file = os.path.join(ProjectPath, "plc.xml")
+ if not os.path.isfile(plc_file):
+ self.NewProject(ProjectPath, BuildPath)
+ else :
+ ProjectController.LoadProject(self, ProjectPath, BuildPath)
+
+ canopen_child = self.GetChildByName("CanOpen")
+ if canopen_child is None:
+ canopen = self.CTNAddChild("CanOpen", "CanOpen", 0)
+ canopen.LoadChildren()
+ canopen.CTNRequestSave()
+
+ if self.CTNTestModified():
+ self.SaveProject()
+
+ self.RefreshConfNodesBlockLists()
+
+ # FIXME XXX
+ if self.arch in PLC_module:
+ self.SetParamsAttribute('BeremizRoot.TargetType', 'MC9')
+
+ return None
+
+ def _UpdateFw(self):
+ """
+ Method called by user to flash the firmware of the PLC
+ """
+ if self.firmwareUpadateIsRunning == True:
+ self.logger.write_error(_("Firmware update is already running!\n"))
+ return
+
+ self.firmwareUpadateIsRunning = True
+ self.logger.write(_("Firmware update started\n"))
+
+ # Launch the firmware selection dialog
+ dialog = FirmwareUpdateDialog(self.AppFrame)
+ answer = dialog.ShowModal()
+ imageFilePath = dialog.GetFirmwareImageFile()
+ updateType = dialog.GetFirmwareUpdateType()
+ chunksSize = dialog.GetChunksSize()
+ reboot = dialog.GetReboot()
+ dialog.Destroy()
+
+ if answer == wx.ID_CANCEL:
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmwareUpadateIsRunning = False
+ return
+
+ if imageFilePath == None or imageFilePath == "":
+ self.logger.write_error(_("No firmware image file selected!\n"))
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmwareUpadateIsRunning = False
+ return
+ else:
+ self.logger.write(_("Firmware image file: %s\n") % imageFilePath)
+
+ if updateType == 1:
+ self.logger.write(_("Firmware update type: Linux kernel image\n"))
+ elif updateType == 2:
+ self.logger.write(_("Firmware update type: Linux DTB image\n"))
+ elif updateType == 3:
+ self.logger.write(_("Firmware update type: Root file system image\n"))
+ else:
+ self.logger.write_error(_("Unknown firmware update type!\n"))
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmwareUpadateIsRunning = False
+ return
+
+ if chunksSize < 1024 or chunksSize > 1024 * 1024:
+ self.logger.write_error(_("Bad chunks size : %d KiB!\n") % chunksSize)
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmwareUpadateIsRunning = False
+ return
+ else:
+ self.logger.write(_("Chunks size : %d KiB\n") % chunksSize)
+
+ self.logger.write(_("Reboot after update : %s\n") % ("Yes" if reboot else "No"))
+ # Get the target PLC URI
+ # Check if an uri is already configured in the Beremiz project
+ uri = self.BeremizRoot.getURI_location()
+ if uri is not None and uri != "":
+ self.logger.write(_("PLC URI configured in the Beremiz project will be used: %s\n") % uri)
+ else:
+ # PLC URI is not configured in the Beremiz project
+ # Launch Service Discovery dialog
+ self.logger.write(_("PLC URI is not configured in the Beremiz project. Launching the Discover dialog\n"))
+ dialog = DiscoveryDialog(self.AppFrame)
+ answer = dialog.ShowModal()
+ uri = dialog.GetURI()
+ dialog.Destroy()
+
+ # Nothing choosed or cancel button
+ if uri is None or answer == wx.ID_CANCEL:
+ self.logger.write_error(_("Connection canceled!\n"))
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmwareUpadateIsRunning = False
+ return
+
+ # Get connector from uri
+ self._connector = None
+ try:
+ self._SetConnector(connectors.ConnectorFactory(uri, self))
+ except Exception:
+ self.logger.write_error(_("Exception while connecting %s!\n") % uri)
+ self.logger.write_error(traceback.format_exc())
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmwareUpadateIsRunning = False
+ return
+
+ # Did connection success ?
+ if self._connector is None:
+ # Oups.
+ self.logger.write_error(_("Connection failed to %s!\n") % uri)
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmwareUpadateIsRunning = False
+ return
+ else:
+ self.logger.write(_("Connected.\n"))
+
+ # Last confirmation before firmware update
+ answer = wx.MessageBox(_('Are you sure to launch the firmware update for the selected PLC?'),
+ _('Firmware Update'), wx.YES_NO | wx.CENTRE | wx.NO_DEFAULT,
+ self.AppFrame)
+ if answer != wx.YES:
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmwareUpadateIsRunning = False
+ return
+ # Some cosmetics
+ self.AppFrame.Refresh()
+ self.AppFrame.Update()
+
+ # Lauch the firmaware update on the remote PLC
+ updater = HostFirmwareUpdater(self._connector, imageFilePath, updateType, chunksSize, reboot, self.logger)
+ try:
+ updater.update()
+ except Exception as e:
+ self.logger.write_error(str(e) + "\n")
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmwareUpadateIsRunning = False
+ self._Disconnect()
+ return
+ self._Disconnect()
+ self.firmwareUpadateIsRunning = False
+ return True
--- a/LPCconnector/LPCAppProto.py Tue Jan 30 14:25:10 2018 +0100
+++ b/LPCconnector/LPCAppProto.py Wed Apr 11 13:06:58 2018 +0200
@@ -115,7 +115,6 @@
LPCAppTransaction.__init__(self, 0x0D)
if __name__ == "__main__":
- __builtins__.BMZ_DBG = True
TestConnection = LPCAppProto(6,115200,2)
# TestConnection.HandleTransaction(GET_PLCIDTransaction())
TestConnection.HandleTransaction(STARTTransaction())
--- a/LPCconnector/LPCBootProto.py Tue Jan 30 14:25:10 2018 +0100
+++ b/LPCconnector/LPCBootProto.py Wed Apr 11 13:06:58 2018 +0200
@@ -60,7 +60,6 @@
return True
if __name__ == "__main__":
- __builtins__.BMZ_DBG = True
TestConnection = LPCBootProto(2,115200,1200)
mystr=file("fw.bin").read()
def mylog(blah):
--- a/LPCconnector/LPCProto.py Tue Jan 30 14:25:10 2018 +0100
+++ b/LPCconnector/LPCProto.py Wed Apr 11 13:06:58 2018 +0200
@@ -14,7 +14,7 @@
class LPCProto:
def __init__(self, port, rate, timeout):
# serialize access lock
- if BMZ_DBG:
+ if False:
# Debugging serial stuff
self._serialPort = serial.Serial( port, rate, timeout = timeout, writeTimeout = timeout )
class myser:
--- a/LPCconnector/PYRO/__init__.py Tue Jan 30 14:25:10 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-# Project name: SmartehIDE
-# __init__.py.py: spacer widget module initialization
-# 19. 01. 2017 12:24 Uporabnik
-#
-# Copyright (c) 2017 Smarteh d.o.o. <info@smarteh.si>
-# THIS PROGRAM COMES WITH NO WARRANTY
-
-import connectors
-import Pyro.core
-from connectors.PYRO import PYRO_connector_factory
-
-oldPYRO_connector_factory = PYRO_connector_factory
-def MW_PYRO_connector_factory(uri, confnodesroot):
- servicetype, location = uri.split("://")
- if servicetype == "PYROS":
- schemename = "PYROLOCSSL"
- else:
- schemename = "PYROLOC"
-
- def CustomFunctionCall(self, funcname, args=None):
- member = self.__dict__.get(funcname, None)
- if member is None:
- def my_local_func(*args, **kwargs):
- funcnameCall = funcname.split('.')[-1]
- return RemoteMWControllerProxy.__getattr__(funcnameCall)(*args, **kwargs)
- member = PyroCatcher(my_local_func, None)
- self.__dict__[funcname] = member
- return member
-
- RemoteMWControllerProxy = Pyro.core.getAttrProxyForURI(schemename + "://" + location + "/MWController")
- pyro_connector = oldPYRO_connector_factory(uri, confnodesroot)
- if pyro_connector:
- pyro_connector.RemoteMWControllerProxy = RemoteMWControllerProxy
- pyro_connector.CustomFunctionCall = CustomFunctionCall
-
- return pyro_connector
-
-PYRO_connector_factory = MW_PYRO_connector_factory
-
-connectors.connectors["PYRO"] = lambda: MW_PYRO_connector_factory
\ No newline at end of file
--- a/LPCconnector/WAMP/__init__.py Tue Jan 30 14:25:10 2018 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,177 +0,0 @@
-# Project name: SmartehIDE
-# __init__.py.py: spacer widget module initialization
-# 19. 01. 2017 12:24 Uporabnik
-#
-# Copyright (c) 2017 Smarteh d.o.o. <info@smarteh.si>
-# THIS PROGRAM COMES WITH NO WARRANTY
-import traceback
-from autobahn.twisted import wamp
-from autobahn.twisted.websocket import WampWebSocketClientFactory, connectWS
-from autobahn.wamp import types
-from autobahn.wamp import auth
-from autobahn.wamp.serializer import MsgPackSerializer
-import connectors
-from twisted.internet import reactor, threads
-from autobahn.wamp.exception import TransportLost
-from threading import Thread, Event
-
-# import connectors.WAMP as WAMP
-# from connectors.WAMP import WAMP_connector_factory, WampSession
-# from threading import _sleep
-
-PLCObjDefaults = { "StartPLC": False,
- "GetTraceVariables" : ("Broken",None),
- "GetPLCstatus" : ("Broken",None),
- "RemoteExec" : (-1, "RemoteExec script failed!")}
-
-PASSWORDS = {
- u'smarteh': u'smarteh'
-}
-
-USER = u'smarteh'
-
-_WampSession = None
-_WampConnection = None
-_WampSessionEvent = Event()
-
-class MWWampSession(wamp.ApplicationSession):
- def onConnect(self):
- self.join(u"Automation", [u"wampcra"], USER)
- print "CRA checking init ..."
-
- def onJoin(self, details):
- global _WampSession, _WampSessionEvent
- _WampSession = self
- _WampSessionEvent.set()
- print 'WAMP session joined for :', self.config.extra["ID"]
-
- def onChallenge(self, challenge):
- if challenge.method == u"wampcra":
- key = PASSWORDS[USER].encode('utf8')
- key = auth.derive_key(key, "salt123", 100, 16)
- signature = auth.compute_wcs(key, challenge.extra['challenge'].encode('utf8'))
- return signature.decode('ascii')
- else:
- raise Exception("don't know how to handle authmethod {}".format(challenge.method))
-
- def onLeave(self, details):
- global _WampSession, _WampSessionEvent
- print details
- self.disconnect()
- _WampSessionEvent.clear()
- _WampSession = None
- print 'WAMP session left'
-
-# DefalutWAMP_connector_factory = WAMP_connector_factory
-
-def MWRegisterWampClient(realm, ID, url, confnodesroot):
- # create a WAMP application session factory
- component_config = types.ComponentConfig(
- realm = unicode(realm),
- extra = {"ID":ID})
- session_factory = wamp.ApplicationSessionFactory(
- config = component_config)
- session_factory.session = MWWampSession
-
- # create a WAMP-over-WebSocket transport client factory
- transport_factory = WampWebSocketClientFactory(
- session_factory,
- url = url+"/beremiz",
- serializers = [MsgPackSerializer()])
- # settings autoPing in seconds
- #transport_factory.autoPingInterval = 60
- #transport_factory.autoPingTimeout = 20
-
- # start the client from a Twisted endpoint
- conn = connectWS(transport_factory)
- confnodesroot.logger.write(_("WAMP connecting to URL : %s\n")%url)
- return conn
-
-def MWWAMP_connector_factory(uri, confnodesroot):
-
- # def CustomFunctionCall(self, funcname, args=None):
- # member = self.__dict__.get(funcname, None)
- # if member is None:
- # member = WampSessionProcMapper(funcname)
- # self.__dict__[funcname] = member
- # return member
- #
- # WAMP.RegisterWampClient = MWRegisterWampClient
- # WAMP.WampSession = MWWampSession
- #
- # wamp_connector = DefalutWAMP_connector_factory(uri, confnodesroot)
- # wamp_connector.CustomFunctionCall = CustomFunctionCall
- # _sleep(1)
- # return wamp_connector
-
- servicetype, location = uri.split("://")
- urlpath, realm, ID = location.split('#')
- urlprefix = {"WAMP": "ws",
- "WAMPS": "wss"}[servicetype]
- url = urlprefix + "://" + urlpath
-
- AddToDoBeforeQuit = confnodesroot.AppFrame.AddToDoBeforeQuit
-
- def ThreadProc():
- global _WampConnection
- _WampConnection = MWRegisterWampClient(realm, ID, url, confnodesroot)
- AddToDoBeforeQuit(reactor.stop)
- reactor.run(installSignalHandlers=False)
-
- def WampSessionProcMapper(funcname):
- wampfuncname = unicode('.'.join((ID, funcname)))
-
- def catcher_func(*args, **kwargs):
- global _WampSession
- if _WampSession is not None:
- try:
- return threads.blockingCallFromThread(
- reactor, _WampSession.call, wampfuncname,
- *args, **kwargs)
- except TransportLost, e:
- confnodesroot.logger.write_error(_("Connection lost!\n"))
- confnodesroot._SetConnector(None)
- except Exception, e:
- errmess = traceback.format_exc()
- confnodesroot.logger.write_error(errmess + "\n")
- print errmess
- # confnodesroot._SetConnector(None)
- return PLCObjDefaults.get(funcname)
-
- return catcher_func
-
- class WampPLCObjectProxy(object):
- def __init__(self):
- global _WampSessionEvent, _WampConnection
- if not reactor.running:
- Thread(target=ThreadProc).start()
- else:
- _WampConnection = threads.blockingCallFromThread(
- reactor, MWRegisterWampClient, realm, ID, url, confnodesroot)
- if not _WampSessionEvent.wait(5):
- _WampConnection = stopConnecting()
- raise Exception, _("WAMP connection timeout")
-
- def __del__(self):
- global _WampConnection
- _WampConnection.disconnect()
- #
- # reactor.stop()
-
- def __getattr__(self, attrName):
- member = self.__dict__.get(attrName, None)
- if member is None:
- member = WampSessionProcMapper(attrName)
- self.__dict__[attrName] = member
- return member
-
- # Try to get the proxy object
- try:
- return WampPLCObjectProxy()
- except Exception, msg:
- confnodesroot.logger.write_error(_("WAMP connection to '%s' failed.\n") % location)
- confnodesroot.logger.write_error(traceback.format_exc())
- return None
-
-
-connectors.connectors["WAMP"] = lambda: MWWAMP_connector_factory
\ No newline at end of file
--- a/LPCconnector/__init__.py Tue Jan 30 14:25:10 2018 +0100
+++ b/LPCconnector/__init__.py Wed Apr 11 13:06:58 2018 +0200
@@ -33,6 +33,5 @@
from LPCBootObject import LPCBootObject
return LPCBootObject(confnodesroot,comportstr)
-connectors.connectors["LPC"] = lambda: LPC_connector_factory
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MC8ProjectController.py Wed Apr 11 13:06:58 2018 +0200
@@ -0,0 +1,895 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+this module is currently _NOT_ imported. It holds LPC customized controller code
+as before stripping MC8 specific customization.
+It is supposed to be imported again once MC8 support fixed
+"""
+
+
+import fnmatch
+import shutil
+import zipfile
+import tempfile
+from ProjectController import ProjectController
+from LPCArch import PLC_module
+
+def mycopytree(src, dst):
+ """
+ Copy content of a directory to an other, omit hidden files
+ @param src: source directory
+ @param dst: destination directory
+ """
+ for i in os.listdir(src):
+ if not i.startswith('.'):
+ srcpath = os.path.join(src, i)
+ dstpath = os.path.join(dst, i)
+ if os.path.isdir(srcpath):
+ if os.path.exists(dstpath):
+ shutil.rmtree(dstpath)
+ os.makedirs(dstpath)
+ mycopytree(srcpath, dstpath)
+ elif os.path.isfile(srcpath):
+ shutil.copy2(srcpath, dstpath)
+
+
+[SIMULATION_MODE, TRANSFER_MODE] = range(2)
+
+# TODO : re-consider customization for MC8
+# from editors.ProjectNodeEditor import ProjectNodeEditor
+# if arch in PLC_module:
+# class LPCProjectNodeEditor(ProjectNodeEditor):
+# pass
+# else:
+# class LPCProjectNodeEditor(ProjectNodeEditor):
+# SHOW_PARAMS = False
+# ENABLE_REQUIRED = False
+
+_StatusMethods = [
+ {"bitmap": "Debug",
+ "name": _("Simulate"),
+ "tooltip": _("Simulate PLC"),
+ "method": "_Simulate"},
+ {"bitmap": "Run",
+ "name": _("Run"),
+ "shown": False,
+ "tooltip": _("Start PLC"),
+ "method": "_Run"},
+ {"bitmap": "Stop",
+ "name": _("Stop"),
+ "shown": False,
+ "tooltip": _("Stop Running PLC"),
+ "method": "_Stop"},
+ {"bitmap": "Build",
+ "name": _("Build"),
+ "tooltip": _("Build project into build folder"),
+ "method": "_Build"},
+ {"bitmap": "Clean",
+ "name": _("Clean"),
+ "enabled": False,
+ "tooltip": _("Clean project build folder"),
+ "method": "_Clean"},
+ {"bitmap": "Transfer",
+ "name": _("Transfer"),
+ "shown": False,
+ "tooltip": _("Transfer PLC"),
+ "method": "_Transfer"},
+]
+_MethodFromPLCState = {
+ "Started": [("_Simulate", False),
+ ("_Run", False),
+ ("_Stop", True),
+ ("_Build", True),
+ ("_Transfer", True)],
+ "Stopped": [("_Simulate", False),
+ ("_Run", True),
+ ("_Stop", False),
+ ("_Build", True),
+ ("_Transfer", True)],
+ "Connected": [("_Simulate", "not simulating"),
+ ("_Run", True),
+ ("_Stop", True), # TODO: if arch in PLC_module else "simulating"),
+ ("_Build", True),
+ ("_Transfer", True)],
+ "Disconnected": [("_Simulate", "not simulating"),
+ ("_Run", False),
+ ("_Stop", False), # TODO: if arch in PLC_module else "simulating"),
+ ("_Build", True),
+ ("_Transfer", False)],
+ "Empty" :[("_Simulate", "not simulating"),
+ ("_Run", False),
+ ("_Stop", False),
+ ("_Build", True),
+ ("_Transfer", True)],
+}
+
+# TODO # if arch in PLC_module:
+_StatusMethods += [
+ {"bitmap": "Connect",
+ "name": _("Connect"),
+ "shown": True,
+ "tooltip": _("Connect to the target PLC"),
+ "method": "_Connect"},
+ {"bitmap": "Disconnect",
+ "name": _("Disconnect"),
+ "shown": False,
+ "tooltip": _("Disconnect from PLC"),
+ "method": "_Disconnect"},
+ {"bitmap": "UpdateFw",
+ "name": _("UpdateFw"),
+ "shown": True,
+ "tooltip": _("Update the PLC firmware"),
+ "method": "_UpdateFw"},
+]
+_MethodFromPLCState["Disconnected"] += [("_Connect", True),
+ ("_Disconnect", False)]
+
+_MethodFromPLCState["Connected"] += [("_Connect", False),
+ ("_Disconnect", True)]
+
+class LPCProjectController(ProjectController):
+ StatusMethods = _StatusMethods
+ # ConfNodeMethods = []
+
+ # TODO : re-consider customization for MC8
+ # EditorType = LPCProjectNodeEditor
+
+ def __init__(self, frame, logger, buildpath, arch):
+ self.arch = arch
+ self.OrigBuildPath = buildpath
+
+ ProjectController.__init__(self, frame, logger)
+
+ self.CTNChildrenTypes += [("LPCBus", LPCBus, "LPC bus"), ("CanOpen", LPCCanOpen, "CanOpen bus")]
+ self.CTNType = "LPC"
+
+ self.OnlineMode = "NORMAL" if self.arch in PLC_module else "OFF"
+ self.LPCConnector = None
+ self.ConnectorPath = None
+
+ self.CurrentMode = None
+ self.previous_mode = None
+
+ self.SimulationBuildPath = None
+
+ self.AbortTransferTimer = None
+
+ # Firmware update running status
+ self.firmawreUpadateIsRunning = False
+ self.building = False
+
+
+ # Bind mouse double click event on URI_location in Beremiz
+ self.UriOptions = True
+
+ def GetProjectName(self):
+ return self.Project.getname()
+
+ def GetDefaultTargetName(self):
+ if self.CurrentMode == SIMULATION_MODE:
+ return ProjectController.GetDefaultTargetName(self)
+ else:
+ return "LPC"
+
+ def GetTarget(self):
+ target = ProjectController.GetTarget(self)
+ if self.CurrentMode != SIMULATION_MODE and self.arch not in PLC_module:
+ target.getcontent().setBuildPath(self.BuildPath)
+ return target
+
+ def _getBuildPath(self):
+ if self.CurrentMode == SIMULATION_MODE:
+ if self.SimulationBuildPath is None:
+ self.SimulationBuildPath = os.path.join(tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build")
+ return self.SimulationBuildPath
+ else:
+ return ProjectController._getBuildPath(self)
+
+ def ToZIPFile(self):
+ # MD5 = self.GetLastBuildMD5()
+ try:
+ path_export_file = self.BuildPath[:-5] + "\\" + self._builder.exe[:-3] + ".xEye"
+ zf = zipfile.ZipFile(path_export_file, mode='w', compression=zipfile.ZIP_DEFLATED)
+ for extrafilespath in [self._getExtraFilesPath(),
+ self._getProjectFilesPath()]:
+ dir = extrafilespath.split("\\")[-1]
+ for name in os.listdir(extrafilespath):
+ zf.write(extrafilespath + '\\' + str(name), dir + '\\' + str(name), zipfile.ZIP_DEFLATED)
+ zf.write(self._builder.exe_path, self._builder.exe)
+ zf.write(self.BuildPath + '\\lastbuildPLC.md5', 'lastbuildPLC.md5')
+ zf.close()
+ self.logger.write(_("Export file is successfully created on location: %s\n") % path_export_file)
+ except Exception, e:
+ self.logger.write(_("Export file is not created because eror: %s\n") % e)
+
+ def _Build(self):
+ self._Clean()
+ save = self.ProjectTestModified()
+ if save:
+ self.SaveProject()
+ self.AppFrame._Refresh(TITLE, FILEMENU)
+ if self.BuildPath is not None:
+ mycopytree(self.OrigBuildPath, self.BuildPath)
+ if ProjectController._Build(self):
+ self.ToZIPFile()
+ if save:
+ wx.CallAfter(self.AppFrame.RefreshAll)
+
+ def SetProjectName(self, name):
+ return self.Project.setname(name)
+
+ def SetOnlineMode(self, mode, path=None):
+ # SetOnlineMode is only for MC8
+ if self.arch in PLC_module:
+ return None
+
+ mode = mode.upper()
+ if self.OnlineMode != mode:
+ if mode not in ["OFF", ""]:
+ self.OnlineMode = mode
+ self.ConnectorPath = path
+ uri = "LPC://%s/%s" % (self.OnlineMode, path)
+ try:
+ self.LPCConnector = connectors.ConnectorFactory(uri, self)
+ except Exception, msg:
+ self.logger.write_error(_("Exception while connecting %s!\n") % uri)
+ self.logger.write_error(traceback.format_exc())
+
+ # Did connection success ?
+ if self.LPCConnector is None:
+ # Oups.
+ self.logger.write_error(_("Connection failed to %s!\n") % uri)
+
+ else:
+ self.OnlineMode = "OFF"
+ self.LPCConnector = None
+ self.ConnectorPath = None
+
+ self.ApplyOnlineMode()
+
+
+ def ApplyOnlineMode(self):
+ if self.CurrentMode != SIMULATION_MODE:
+ self.KillDebugThread()
+
+ self._SetConnector(self.LPCConnector)
+
+ # Init with actual PLC status and print it
+ self.UpdateMethodsFromPLCStatus()
+
+ if self.LPCConnector is not None and self.OnlineMode == "APPLICATION":
+
+ self.CompareLocalAndRemotePLC()
+
+ if self.previous_plcstate is not None:
+ status = _(self.previous_plcstate)
+ else:
+ status = ""
+ self.logger.write(_("PLC is %s\n") % status)
+
+ # if self.StatusTimer and not self.StatusTimer.IsRunning():
+ # # Start the status Timer
+ # self.StatusTimer.Start(milliseconds=2000, oneShot=False)
+
+ if self.previous_plcstate == "Started":
+ if self.DebugAvailable() and self.GetIECProgramsAndVariables():
+ self.logger.write(_("Debug connect matching running PLC\n"))
+ self._connect_debug()
+ else:
+ self.logger.write_warning(_("Debug do not match PLC - stop/transfert/start to re-enable\n"))
+
+ elif self.StatusTimer and self.StatusTimer.IsRunning():
+ self.StatusTimer.Stop()
+
+ if self.CurrentMode == TRANSFER_MODE:
+
+ if self.OnlineMode == "BOOTLOADER":
+ self.BeginTransfer()
+
+ elif self.OnlineMode == "APPLICATION":
+ self.CurrentMode = None
+ self.AbortTransferTimer.Stop()
+ self.AbortTransferTimer = None
+
+ self.logger.write(_("PLC transferred successfully\n"))
+
+ # Update a PLCOpenEditor Pou variable location
+ def UpdateProjectVariableLocation(self, old_leading, new_leading):
+ self.Project.updateElementAddress(old_leading, new_leading)
+ self.BufferProject()
+
+ # Update a PLCOpenEditor Pou variable name
+ def UpdateProjectVariableName(self, old_name, new_name):
+ self.Project.updateElementName(old_name, new_name)
+ self.BufferProject()
+
+ def RemoveProjectVariableByAddress(self, address):
+ self.Project.removeVariableByAddress(address)
+ self.BufferProject()
+
+ def RemoveProjectVariableByFilter(self, leading):
+ self.Project.removeVariableByFilter(leading)
+ self.BufferProject()
+
+ def AddProjectDefaultConfiguration(self, config_name="config", res_name="resource1"):
+ ProjectController.AddProjectDefaultConfiguration(self, config_name, res_name)
+
+ self.SetEditedResourceInfos(
+ self.ComputeConfigurationResourceName(config_name, res_name),
+ [{"Name": "main_task",
+ "Triggering": "Cyclic",
+ "Interval": "T#50ms",
+ "Priority": 0}],
+ [])
+
+ def LoadProject(self, ProjectPath, BuildPath=None):
+ """
+ Load a project contained in a folder
+ @param ProjectPath: path of the project folder
+ """
+ if os.path.basename(ProjectPath) == "":
+ ProjectPath = os.path.dirname(ProjectPath)
+
+ # Verify that project contains a PLCOpen program
+ plc_file = os.path.join(ProjectPath, "plc.xml")
+ if os.path.isfile(plc_file):
+ # Load PLCOpen file
+ result = self.OpenXMLFile(plc_file)
+ if result:
+ return result
+ else:
+ self.CreateNewProject({"companyName": "",
+ "productName": "",
+ "productVersion": "",
+ "projectName": "",
+ "pageSize": (0, 0),
+ "scaling": {}})
+ if len(self.GetProjectConfigNames()) == 0:
+ self.AddProjectDefaultConfiguration()
+
+ # Change XSD into class members
+ self._AddParamsMembers()
+ self.Children = {}
+
+ # Keep track of the root confnode (i.e. project path)
+ self.ProjectPath = ProjectPath
+
+ self.BuildPath = self._getBuildPath()
+ if self.OrigBuildPath is not None:
+ mycopytree(self.OrigBuildPath, self.BuildPath)
+
+ # If dir have already be made, and file exist
+ if os.path.isdir(self.CTNPath()) and os.path.isfile(self.ConfNodeXmlFilePath()):
+ # Load the confnode.xml file into parameters members
+ result = self.LoadXMLParams()
+ if result:
+ return result
+ # Load and init all the children
+ self.LoadChildren()
+
+ canopen_child = self.GetChildByName("CanOpen")
+ if canopen_child is None:
+ canopen = self.CTNAddChild("CanOpen", "CanOpen", 0)
+ canopen.LoadChildren()
+ canopen.CTNRequestSave()
+
+ if self.CTNTestModified():
+ self.SaveProject()
+
+ if wx.GetApp() is None:
+ self.RefreshConfNodesBlockLists()
+ else:
+ wx.CallAfter(self.RefreshConfNodesBlockLists)
+
+ if self.arch in PLC_module:
+ self.SetParamsAttribute('BeremizRoot.TargetType', 'MC9')
+
+ return None
+
+ def IsPLCStarted(self):
+ return self.previous_plcstate == "Started" or self.previous_mode == SIMULATION_MODE
+
+ def ShowMethod(self, name, val):
+ simulating = self.CurrentMode == SIMULATION_MODE
+ if type(val) == str:
+ if val.endswith("simulating"):
+ if val.startswith("not"):
+ val = not simulating
+ else:
+ val = simulating
+
+ ProjectController.ShowMethod(self, name, val)
+
+ def UpdateMethodsFromPLCStatus(self):
+ simulating = self.CurrentMode == SIMULATION_MODE
+ if self.OnlineMode == "OFF":
+ if simulating:
+ status, log_count = self._connector.GetPLCstatus()
+ self.UpdatePLCLog(log_count)
+ status = "Disconnected"
+ elif self.OnlineMode == "BOOTLOADER":
+ status = "Connected"
+ else:
+ if self._connector is not None:
+ status, log_count = self._connector.GetPLCstatus()
+ if status == "Disconnected":
+ self._SetConnector(None, False)
+ else:
+ self.UpdatePLCLog(log_count)
+ else:
+ status = "Disconnected"
+ if self.previous_plcstate != status or self.previous_mode != self.CurrentMode:
+ for args in _MethodFromPLCState.get(status, []):
+ self.ShowMethod(*args)
+ self.previous_plcstate = status
+ self.previous_mode = self.CurrentMode
+ if self.AppFrame is not None:
+ self.AppFrame.RefreshStatusToolBar()
+ connection_text = _("Connected to: ")
+ status_text = ""
+ if simulating:
+ connection_text += _("Simulation")
+ status_text += _("ON")
+ if status == "Disconnected":
+ if not simulating:
+ self.AppFrame.ConnectionStatusBar.SetStatusText(_(status), 1)
+ self.AppFrame.ConnectionStatusBar.SetStatusText('', 2)
+ else:
+ self.AppFrame.ConnectionStatusBar.SetStatusText(connection_text, 1)
+ self.AppFrame.ConnectionStatusBar.SetStatusText(status_text, 2)
+ else:
+ if simulating:
+ connection_text += " (%s)"
+ status_text += " (%s)"
+ else:
+ connection_text += "%s"
+ status_text += "%s"
+ self.AppFrame.ConnectionStatusBar.SetStatusText(connection_text % self.ConnectorPath, 1)
+ self.AppFrame.ConnectionStatusBar.SetStatusText(status_text % _(status), 2)
+ return True
+ return False
+
+ def Generate_plc_declare_locations(self):
+ """
+ Declare used locations in order to simulatePLC in a black box
+ """
+ return """#include "iec_types_all.h"
+
+#define __LOCATED_VAR(type, name, ...) \
+type beremiz_##name;\
+type *name = &beremiz_##name;
+
+#include "LOCATED_VARIABLES.h"
+
+#undef __LOCATED_VAR
+
+"""
+
+ def Generate_lpc_retain_array_sim(self):
+ """
+ Support for retain array in Simulation
+ """
+ return """/* Support for retain array */
+#define USER_RETAIN_ARRAY_SIZE 2000
+#define NUM_OF_COLS 3
+unsigned char readOK = 0;
+unsigned int foundIndex = USER_RETAIN_ARRAY_SIZE;
+unsigned int retainArray[USER_RETAIN_ARRAY_SIZE][NUM_OF_COLS];
+
+unsigned int __GetRetainData(unsigned char READ, unsigned int INDEX, unsigned int COLUMN)
+{
+ if(READ == 1)
+ {
+ if((0<=INDEX) && (INDEX<USER_RETAIN_ARRAY_SIZE) && (0<=COLUMN) && (COLUMN<NUM_OF_COLS))
+ {
+ readOK = 1;
+ return retainArray[INDEX][COLUMN];
+ }
+ }
+
+ readOK = 0;
+ return 0;
+}
+
+unsigned char __SetRetainData(unsigned char WRITE, unsigned int INDEX, unsigned int WORD1, unsigned int WORD2, unsigned int WORD3)
+{
+ if(WRITE == 1)
+ {
+ if((0<=INDEX) && (INDEX<USER_RETAIN_ARRAY_SIZE))
+ {
+ retainArray[INDEX][0] = WORD1;
+ retainArray[INDEX][1] = WORD2;
+ retainArray[INDEX][2] = WORD3;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+unsigned char __FindRetainData(unsigned char SEARCH, unsigned int START_IDX, unsigned int END_IDX, unsigned int WORD1, unsigned int WORD2, unsigned int WORD3)
+{
+ unsigned int i;
+
+ if((SEARCH==1) && (0<=START_IDX) && (START_IDX<USER_RETAIN_ARRAY_SIZE) && (START_IDX<=END_IDX) && (END_IDX<USER_RETAIN_ARRAY_SIZE))
+ {
+ for(i=START_IDX;i<=END_IDX;i++)
+ {
+ if((retainArray[i][0] == WORD1) && (retainArray[i][1] == WORD2) && (retainArray[i][2] == WORD3))
+ {
+ foundIndex = i;
+ return 1;
+ }
+ }
+ }
+
+ foundIndex = USER_RETAIN_ARRAY_SIZE; /* Data not found => return index that is out of array bounds */
+ return 0;
+}
+
+/* Since Beremiz debugger doesn't like pointer-by-reference stuff or global varibles, separate function is a must */
+unsigned char __GetReadStatus(unsigned char dummy)
+{
+ return readOK;
+}
+
+unsigned int __GetFoundIndex(unsigned char dummy)
+{
+ return foundIndex;
+}
+"""
+
+ def _Simulate(self):
+ """
+ Method called by user to Simulate PLC
+ """
+ uri = "LOCAL://"
+ try:
+ self._SetConnector(connectors.ConnectorFactory(uri, self))
+ except Exception, msg:
+ self.logger.write_error(_("Exception while connecting %s!\n") % uri)
+ self.logger.write_error(traceback.format_exc())
+
+ # Did connection success ?
+ if self._connector is None:
+ # Oups.
+ self.logger.write_error(_("Connection failed to %s!\n") % uri)
+ self.StopSimulation()
+ return False
+
+ self.CurrentMode = SIMULATION_MODE
+
+ buildpath = self._getBuildPath()
+
+ # Eventually create build dir
+ if not os.path.exists(buildpath):
+ os.makedirs(buildpath)
+
+ # Generate SoftPLC IEC code
+ IECGenRes = self._Generate_SoftPLC()
+
+ # If IEC code gen fail, bail out.
+ if not IECGenRes:
+ self.logger.write_error(_("IEC-61131-3 code generation failed !\n"))
+ self.StopSimulation()
+ return False
+
+ # Reset variable and program list that are parsed from
+ # CSV file generated by IEC2C compiler.
+ self.ResetIECProgramsAndVariables()
+
+ gen_result = self.CTNGenerate_C(buildpath, self.PLCGeneratedLocatedVars)
+ CTNCFilesAndCFLAGS, CTNLDFLAGS, DoCalls = gen_result[:3]
+ # if some files have been generated put them in the list with their location
+ if CTNCFilesAndCFLAGS:
+ self.LocationCFilesAndCFLAGS = [(self.GetCurrentLocation(), CTNCFilesAndCFLAGS, DoCalls)]
+ else:
+ self.LocationCFilesAndCFLAGS = []
+
+ # confnode asks for some LDFLAGS
+ if CTNLDFLAGS:
+ # LDFLAGS can be either string
+ if type(CTNLDFLAGS) == type(str()):
+ self.LDFLAGS = [CTNLDFLAGS]
+ # or list of strings
+ elif type(CTNLDFLAGS) == type(list()):
+ self.LDFLAGS = CTNLDFLAGS[:]
+ else:
+ self.LDFLAGS = []
+
+ # Header file for extensions
+ open(os.path.join(buildpath, "beremiz.h"), "w").write(targets.GetHeader())
+
+ # Template based part of C code generation
+ # files are stacked at the beginning, as files of confnode tree root
+ for generator, filename, name in [
+ # debugger code
+ (self.Generate_plc_debugger, "plc_debugger.c", "Debugger"),
+ # init/cleanup/retrieve/publish, run and align code
+ (self.Generate_plc_main, "plc_main.c", "Common runtime"),
+ # declare located variables for simulate in a black box
+ (self.Generate_plc_declare_locations, "plc_declare_locations.c", "Declare Locations"),
+ # declare located variables for simulate in a black box
+ (self.Generate_lpc_retain_array_sim, "lpc_retain_array_sim.c", "Retain Array for Simulation")]:
+ try:
+ # Do generate
+ code = generator()
+ if code is None:
+ raise
+ code_path = os.path.join(buildpath, filename)
+ open(code_path, "w").write(code)
+ # Insert this file as first file to be compiled at root confnode
+ self.LocationCFilesAndCFLAGS[0][1].insert(0, (code_path, self.plcCFLAGS))
+ except Exception, exc:
+ self.logger.write_error(name + _(" generation failed !\n"))
+ self.logger.write_error(traceback.format_exc())
+ self.StopSimulation()
+ return False
+
+ # Get simulation builder
+ builder = self.GetBuilder()
+ if builder is None:
+ self.logger.write_error(_("Fatal : cannot get builder.\n"))
+ self.StopSimulation()
+ return False
+
+ # Build
+ try:
+ if not builder.build():
+ self.logger.write_error(_("C Build failed.\n"))
+ self.StopSimulation()
+ return False
+ except Exception, exc:
+ self.logger.write_error(_("C Build crashed !\n"))
+ self.logger.write_error(traceback.format_exc())
+ self.StopSimulation()
+ return False
+
+ data = builder.GetBinaryCode()
+ if data is not None:
+ if self._connector.NewPLC(builder.GetBinaryCodeMD5(), data, []):
+ self.UnsubscribeAllDebugIECVariable()
+ self.ProgramTransferred()
+ if self.AppFrame is not None:
+ self.AppFrame.CloseObsoleteDebugTabs()
+ self.AppFrame.RefreshPouInstanceVariablesPanel()
+ self.logger.write(_("Transfer completed successfully.\n"))
+ else:
+ self.logger.write_error(_("Transfer failed\n"))
+ self.StopSimulation()
+ return False
+
+ self._Run()
+
+ if not self.StatusTimer.IsRunning():
+ # Start the status Timer
+ self.StatusTimer.Start(milliseconds=500, oneShot=False)
+
+ def StopSimulation(self):
+ self.CurrentMode = None
+ self._SetConnector(None, False)
+ self.ApplyOnlineMode()
+
+ def _Stop(self):
+ ProjectController._Stop(self)
+
+ if self.CurrentMode == SIMULATION_MODE:
+ self.StopSimulation()
+
+ def CompareLocalAndRemotePLC(self):
+ # if self.LPCConnector is None:
+ # return
+ if self._connector is None:
+ return
+ # We are now connected. Update button status
+ MD5 = self.GetLastBuildMD5()
+ # Check remote target PLC correspondance to that md5
+ # if MD5 is not None and self.LPCConnector.MatchMD5(MD5):
+ if MD5 is not None and self._connector.MatchMD5(MD5):
+ # warns controller that program match
+ self.ProgramTransferred()
+
+ def ResetBuildMD5(self):
+ builder = self.GetBuilder()
+ if builder is not None:
+ builder.ResetBinaryCodeMD5(*([] if self.arch in PLC_module else [self.OnlineMode]))
+
+ def GetLastBuildMD5(self):
+ builder = self.GetBuilder()
+ if builder is not None:
+ return builder.GetBinaryCodeMD5(*([] if self.arch in PLC_module else [self.OnlineMode]))
+ else:
+ return None
+
+ def _Clean(self, building = False):
+ self._CloseView(self._IECCodeView)
+ runtime_list = fnmatch.filter(os.listdir(self._getBuildPath()), 'runtime_*')
+ if os.path.isdir(os.path.join(self._getBuildPath())) and os.path.isfile(
+ os.path.join(self._getBuildPath(), "hmi.py")) or runtime_list != []:
+ self.logger.write(_("Cleaning the build directory\n"))
+ # self.logger.write(_(str(os.path.join(self._getBuildPath(), "hmi.py"))))
+ for file in runtime_list:
+ os.remove(os.path.join(self._getBuildPath(), file))
+ if os.path.isfile(os.path.join(self._getBuildPath(), "hmi.py")):
+ os.remove(os.path.join(self._getBuildPath(), "hmi.py"))
+ else:
+ if not building:
+ self.logger.write_error(_("Build directory already clean\n"))
+ self.ShowMethod("_showIECcode", False)
+ self.EnableMethod("_Clean", False)
+ # kill the builder
+ self._builder = None
+ self.CompareLocalAndRemotePLC()
+
+ def _Transfer(self):
+ if self.OnlineMode == "NORMAL":
+ if self.IsPLCStarted():
+ dialog = wx.MessageDialog(self.AppFrame, "You must stop the PLC before transfer. Do you want to stop it now and transfer?", style=wx.YES_NO|wx.CENTRE)
+ if dialog.ShowModal() == wx.ID_YES:
+ self._Stop()
+ else:
+ return
+ ProjectController._Transfer(self)
+ return
+ if self.CurrentMode is None and self.OnlineMode != "OFF":
+ self.CurrentMode = TRANSFER_MODE
+
+ if ProjectController._Build(self):
+
+ ID_ABORTTRANSFERTIMER = wx.NewId()
+ self.AbortTransferTimer = wx.Timer(self.AppFrame, ID_ABORTTRANSFERTIMER)
+ self.AppFrame.Bind(wx.EVT_TIMER, self.AbortTransfer, self.AbortTransferTimer)
+
+ if self.OnlineMode == "BOOTLOADER":
+ self.BeginTransfer()
+
+ else:
+ self.logger.write(_("Resetting PLC\n"))
+ # self.StatusTimer.Stop()
+ self.LPCConnector.ResetPLC()
+ self.AbortTransferTimer.Start(milliseconds=5000, oneShot=True)
+
+ else:
+ self.CurrentMode = None
+
+ def BeginTransfer(self):
+ self.logger.write(_("Start PLC transfer\n"))
+
+ self.AbortTransferTimer.Stop()
+ ProjectController._Transfer(self)
+ self.AbortTransferTimer.Start(milliseconds=5000, oneShot=True)
+
+ def AbortTransfer(self, event):
+ self.logger.write_warning(_("Timeout waiting PLC to recover\n"))
+
+ self.CurrentMode = None
+ self.AbortTransferTimer.Stop()
+ self.AbortTransferTimer = None
+ event.Skip()
+
+ def _UpdateFw(self):
+ """
+ Method called by user to flash the firmware of the PLC
+ """
+ from FirmwareUpdateDialog import FirmwareUpdateDialog
+ from dialogs import DiscoveryDialog
+ from HostFirmwareUpdater import HostFirmwareUpdater
+
+ if self.firmawreUpadateIsRunning == True:
+ self.logger.write_error(_("Firmware update is already running!\n"))
+ return
+
+ self.firmawreUpadateIsRunning = True
+ self.logger.write(_("Firmware update started\n"))
+
+ # Launch the firmware selection dialog
+ dialog = FirmwareUpdateDialog(self.AppFrame)
+ answer = dialog.ShowModal()
+ imageFilePath = dialog.GetFirmwareImageFile()
+ updateType = dialog.GetFirmwareUpdateType()
+ chunksSize = dialog.GetChunksSize()
+ reboot = dialog.GetReboot()
+ dialog.Destroy()
+
+ if answer == wx.ID_CANCEL:
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmawreUpadateIsRunning = False
+ return
+
+ if imageFilePath == None or imageFilePath == "":
+ self.logger.write_error(_("No firmware image file selected!\n"))
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmawreUpadateIsRunning = False
+ return
+ else:
+ self.logger.write(_("Firmware image file: %s\n") % imageFilePath)
+
+ if updateType == 1:
+ self.logger.write(_("Firmware update type: Linux kernel image\n"))
+ elif updateType == 2:
+ self.logger.write(_("Firmware update type: Linux DTB image\n"))
+ elif updateType == 3:
+ self.logger.write(_("Firmware update type: Root file system image\n"))
+ else:
+ self.logger.write_error(_("Unknown firmware update type!\n"))
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmawreUpadateIsRunning = False
+ return
+
+ if chunksSize < 1024 or chunksSize > 1024 * 1024:
+ self.logger.write_error(_("Bad chunks size : %d KiB!\n") % chunksSize)
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmawreUpadateIsRunning = False
+ return
+ else:
+ self.logger.write(_("Chunks size : %d KiB\n") % chunksSize)
+
+ self.logger.write(_("Reboot after update : %s\n") % ("Yes" if reboot else "No"))
+ # Get the target PLC URI
+ # Check if an uri is already configured in the Beremiz project
+ uri = self.BeremizRoot.getURI_location()
+ if uri is not None and uri != "":
+ self.logger.write(_("PLC URI configured in the Beremiz project will be used: %s\n") % uri)
+ else:
+ # PLC URI is not configured in the Beremiz project
+ # Launch Service Discovery dialog
+ self.logger.write(_("PLC URI is not configured in the Beremiz project. Launching the Discover dialog\n"))
+ dialog = DiscoveryDialog(self.AppFrame)
+ answer = dialog.ShowModal()
+ uri = dialog.GetURI()
+ dialog.Destroy()
+
+ # Nothing choosed or cancel button
+ if uri is None or answer == wx.ID_CANCEL:
+ self.logger.write_error(_("Connection canceled!\n"))
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmawreUpadateIsRunning = False
+ return
+
+ # Get connector from uri
+ self._connector = None
+ try:
+ self._SetConnector(connectors.ConnectorFactory(uri, self))
+ except Exception:
+ self.logger.write_error(_("Exception while connecting %s!\n") % uri)
+ self.logger.write_error(traceback.format_exc())
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmawreUpadateIsRunning = False
+ return
+
+ # Did connection success ?
+ if self._connector is None:
+ # Oups.
+ self.logger.write_error(_("Connection failed to %s!\n") % uri)
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmawreUpadateIsRunning = False
+ return
+ else:
+ self.logger.write(_("Connected.\n"))
+
+ # Last confirmation before firmware update
+ answer = wx.MessageBox(_('Are you sure to launch the firmware update for the selected PLC?'),
+ _('Firmware Update'), wx.YES_NO | wx.CENTRE | wx.NO_DEFAULT,
+ self.AppFrame)
+ if answer != wx.YES:
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmawreUpadateIsRunning = False
+ return
+ # Some cosmetics
+ self.AppFrame.Refresh()
+ self.AppFrame.Update()
+
+ # Lauch the firmaware update on the remote PLC
+ updater = HostFirmwareUpdater(self._connector, imageFilePath, updateType, chunksSize, reboot, self.logger)
+ try:
+ updater.update()
+ except Exception as e:
+ self.logger.write_error(str(e) + "\n")
+ self.logger.write_error(_("Firmware update canceled!\n"))
+ self.firmawreUpadateIsRunning = False
+ self._Disconnect()
+ return
+ self._Disconnect()
+ self.firmawreUpadateIsRunning = False
+ return True
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/StdoutPseudoFile.py Wed Apr 11 13:06:58 2018 +0200
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import socket
+
+class StdoutPseudoFile:
+ def __init__(self, port, debug):
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.socket.connect(('localhost', port))
+ self.Buffer = ""
+ self.debug = debug
+
+ def __del__(self):
+ self.socket.close()
+
+ def readline(self):
+ idx = self.Buffer.find("\n")
+ while idx == -1:
+ text = self.socket.recv(2048)
+ if text == "":
+ return ""
+ self.Buffer += text
+ idx = self.Buffer.find("\n")
+ if idx != -1:
+ line = self.Buffer[:idx + 1]
+ self.Buffer = self.Buffer[idx + 1:]
+ if self.debug:
+ print "command >" + line
+ return line
+ return ""
+
+ """ Base class for file like objects to facilitate StdOut for the Shell."""
+
+ def write(self, s, style=None):
+ if s != '':
+ self.socket.send(s.encode('utf8'))
+
+ def writeyield(self, s):
+ self.write(s)
+
+ def write_warning(self, s):
+ self.write(s)
+
+ def write_error(self, s):
+ self.write(s)
+
+ def flush(self):
+ pass
+
+ def isatty(self):
+ return False
+