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 @@
--- /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 @@
+PLC_GOT_module = ['GOT', 'GOT_111', 'GOT_131'] +PLC_MC9_module = ['MC9'] +PLC_module = PLC_MC9_module + PLC_GOT_module --- /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 @@
+from __future__ import absolute_import +from BeremizIDE import * +from VariableExporter import VariableWriter +# XXX TODO : strip dead code. document. +class LPCBeremiz(Beremiz): + def _init_coll_FileMenu_Items(self, parent): + config = wx.ConfigBase.Get() + export = str(config.Read("Exporter")) + config.Write("Exporter", '0') + 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() + 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) + 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): + 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")): + self.CTR.ResetAppFrame(self.lpcberemiz_cmd_pipe) + self.CTR.KillDebugThread() + self.KillLocalRuntime() + self.lpcberemiz_cmd_pipe.write("Closed\n") + def RefreshTitle(self): + if self.CTR is not None: + projectname = self.CTR.GetProjectName() + if self.CTR.ProjectTestModified(): + projectname = "~%s~" % projectname + self.SetTitle("%s - %s" % (name, projectname)) + def RefreshFileMenu(self): + MenuToolBar = self.Panes["MenuToolBar"] + if self.CTR is not None: + selected = self.TabsOpened.GetSelection() + graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer) + if self.TabsOpened.GetPageCount() > 0: + self.FileMenu.Enable(wx.ID_CLOSE, True) + self.FileMenu.Enable(wx.ID_PREVIEW, True) + self.FileMenu.Enable(wx.ID_PRINT, True) + MenuToolBar.EnableTool(wx.ID_PRINT, True) + 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_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) + 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() + 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) + 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 modpath = os.path.split(__file__)[0]
+from LPCArch import GetLPCArch, PLC_module + bus_template_name = "MC9" + bus_template_name = arch return open(os.path.join(modpath,"LPCBus",fname)).read()
@@ -17,10 +26,6 @@
LPCBusLDFLAGS = { "MC9:On Board" : "-lmbrtu" }
-# to be overloaded at import
from plcopen.structures import LOCATIONDATATYPES
from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP,\
@@ -281,7 +286,7 @@
code_str["publish_code"] += " " + var["Publish"] % ("*" + var["location"]) + "\n"
- BusName = LPCarch + ":" + self.BaseParams.getName()
+ BusName = bus_template_name + ":" + self.BaseParams.getName() @@ -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) 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 @@
+from __future__ import absolute_import +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 + return str(defaultGetCFLAGS(*args)) + return str(defaultGetLDFLAGS(*args)) +canfestival.local_canfestival_config.getCFLAGS = getCFLAGS +canfestival.local_canfestival_config.getLDFLAGS = getLDFLAGS + "CAN_Baudrate": "125K", +class LPCSlaveEditor(SlaveEditor): + # SHOW_BASE_PARAMS = False +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: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:restriction base="xsd:integer"> + <xsd:minInclusive value="1"/> + <xsd:maxInclusive value="99"/> + EditorType = LPCSlaveEditor + # TODO change netname when name change + NodeManager.__init__(self) + odfilepath = self.GetSlaveODPath() + if (os.path.isfile(odfilepath)): + self.OpenFileInCurrent(odfilepath) + self.CreateNewNode("SlaveNode", # Name - will be changed at build time + 0x00, # NodeID - will be changed at build time + def GetCanDevice(self): + return str(self.BaseParams.getIEC_Channel()) + {"bitmap": "NetworkEdit", + "name": _("Edit slave"), + "tooltip": _("Edit CanOpen slave with ObjdictEdit"), + "method": "_OpenView"}, + ] + _SlaveCTN.ConfNodeMethods +class LPCNetworkEditor(NetworkEditor): + # SHOW_BASE_PARAMS = False +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: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"/> + EditorType = LPCNetworkEditor + def GetCanDevice(self): + return str(self.BaseParams.getIEC_Channel()) + {"bitmap": "NetworkEdit", + "name": _("Edit network"), + "tooltip": _("Edit CanOpen Network with NetworkEdit"), + "method": "_OpenView"}, + ] + _NodeListCTN.ConfNodeMethods +class LPCCanOpen(CanOpenRootClass): + CTNChildrenTypes = [("CanOpenNode", LPCCanOpenMaster, "CanOpen Master"), + ("CanOpenSlave", LPCCanOpenSlave, "CanOpen Slave")] + def GetCanDriver(self): + 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) --- /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 @@
+from __future__ import absolute_import +from threading import Thread, Semaphore, Lock, Timer +from types import StringType, UnicodeType +from PLCControler import LOCATION_MODULE, LOCATION_GROUP +wx_eval_lock = Semaphore(0) +# Command log for debug, for viewing from wxInspector +# __builtins__.cmdlog = [] +def wx_evaluator(callable, *args, **kwargs): + eval_res = callable(*args, **kwargs) +def evaluator(callable, *args, **kwargs): + wx.CallAfter(wx_evaluator, callable, *args, **kwargs) + return tuple(map(int, loc.split("."))) +class LPCCommand(cmd.Cmd): + 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 + for function, (arg_types, opt) in [ + ("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") + for num, arg in enumerate(args_toks): + args.extend(stripped.split(" ")) + if opt == 0 and len(args) != arg_number: + elif len(args) > arg_number: + elif len(args) < arg_number - opt: + number = arg_number - opt + self.Log.write("Error: No argument%s expected for %s\n" % (extra, function)) + self.Log.write("Error: 1 argument%s expected for %s\n" % (extra, function)) + self.Log.write("Error: %d arguments%s expecte for %s\n" % (number, extra, function)) + for num, arg in enumerate(args): + args[num] = arg_types[num](arg) + self.Log.write("Error: Invalid value for argument %d\n" % (num + 1)) + func = getattr(self, function) + res = evaluator(func, *args) + # cmdlog.append((function, line, res)) + # if len(cmdlog) > 100: # prevent debug log to grow too much + if isinstance(res, (StringType, UnicodeType)): + 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() + self.Launcher.app.ExitMainLoop() + def do_EOF(self, line): + def Show(self, loading=False): + Doesn't do anything on MC9 + Was usefull at some time on MC8... + if self.Launcher.frame is not None: + if self.restore_last_state: + self.restore_last_state = False + self.Launcher.frame.RestoreLastState() + self.Launcher.frame.RefreshEditor() + self.Launcher.frame.RefreshAfterLoad() + self.Launcher.frame.RefreshAll() + self.CTR.ResetAppFrame(self.Log) + if self.Launcher.frame is not None: + self.Launcher.frame.Hide() + def SetProjectProperties(self, projectname, productname, productversion, companyname): + "projectName": projectname, + "productName": productname, + "productVersion": productversion, + "companyName": companyname} + self.CTR.SetProjectProperties(properties=new_properties, buffer=False) + def SetOnlineMode(self, mode, path=None): + self.CTR.SetOnlineMode(mode, path) + 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) + return "Error: Unable to create bus\n" + def RenameBus(self, iec_channel, name): + bus = self.CTR.GetChildByIECLocation((iec_channel,)) + 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) + def ChangeBusIECChannel(self, old_iec_channel, new_iec_channel): + bus = self.CTR.GetChildByIECLocation((old_iec_channel,)) + 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), + bus.BaseParams.setIEC_Channel(new_iec_channel) + def RemoveBus(self, iec_channel): + bus = self.CTR.GetChildByIECLocation((iec_channel,)) + return "Error: No bus found\n" + self.CTR.RemoveProjectVariableByFilter(str(iec_channel)) + self.CTR.Children["LPCBus"].remove(bus) + def AddModule(self, parent, iec_channel, name, icode, icon=None): + module = self.CTR.GetChildByIECLocation(parent) + 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, + def RenameModule(self, iec_location, name): + module = self.CTR.GetChildByIECLocation(iec_location) + return "Error: No module found\n" + parent = self.CTR.GetChildByIECLocation(iec_location[:-1]) + 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 + def ChangeModuleIECChannel(self, old_iec_location, new_iec_channel): + module = self.CTR.GetChildByIECLocation(old_iec_location) + return "Error: No module found\n" + parent = self.CTR.GetChildByIECLocation(old_iec_location[:-1]) + 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 + def ChangeModuleInitCode(self, iec_location, icode): + module = self.CTR.GetChildByIECLocation(iec_location) + return "Error: No module found\n" + def RemoveModule(self, parent, iec_channel): + module = self.CTR.GetChildByIECLocation(parent) + return "Error: No parent found\n" + child = GetModuleBySomething(module, "IEC_Channel", (iec_channel,)) + return "Error: No module found\n" + self.CTR.RemoveProjectVariableByFilter(".".join(map(str, parent + (iec_channel,)))) + RemoveModuleChild(module, child) + def StartGroup(self, parent, name, icon=None): + module = self.CTR.GetChildByIECLocation(parent) + 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, + def AddVariable(self, parent, location, name, direction, type, rcode, pcode, description=""): + module = self.CTR.GetChildByIECLocation(parent) + 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, + "type": LOCATION_TYPES[direction], + "description": description, + def ChangeVariableParams(self, parent, location, new_name, new_direction, new_type, new_rcode, new_pcode, + module = self.CTR.GetChildByIECLocation(parent) + return "Error: No parent found\n" + for child in GetModuleChildren(module): + if child["location"] == location and child["type"] == LOCATION_TYPES[new_direction]: + elif child["name"] == new_name: + return "Error: A variable named %s already exists\n" % new_name + 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 + def RemoveVariable(self, parent, location, direction): + module = self.CTR.GetChildByIECLocation(parent) + return "Error: No parent found\n" + child = GetModuleVariable(module, location, direction) + 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) --- /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 @@
+from __future__ import absolute_import +# --------- Libraries Extension ------------ +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')] + 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")))] + 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 ------------ +from LPCconnector import LPC_connector_factory +connectors.connectors["LPC"] = lambda: LPC_connector_factory +# --------- Targets/Toolchains Extension ------------ +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 @@
+from __future__ import absolute_import +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)
-from types import StringType, UnicodeType
+from util.BitmapLibrary import AddBitmapFolder # Path of directory containing current python file
_lpcmanager_path = os.path.split(__file__)[0]
-PLC_GOT_module = ['GOT', 'GOT_111', 'GOT_131']
-PLC_MC9_module = ['MC9']
-PLC_module = PLC_MC9_module + PLC_GOT_module
- print "\nUsage of LPCManager.py :"
- print "\n %s Projectpath Buildpath port arch\n" % sys.argv[0]
-# Command line arguments parsing
- opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
-except getopt.GetoptError:
- # print help information and exit:
-# asking for help causes exit
- if o in ("-h", "--help"):
-# 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)
- 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]
-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)]
- 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)
-from LPCconnector import LPC_connector_factory
-from LPCconnector.PYRO import MW_PYRO_connector_factory
-from LPCconnector.WAMP import MWWAMP_connector_factory
-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((
- for varinfo in varinfos])
- # Runtime calls (start, stop, init, and cleanup)
- for section in self.SECTIONS_NAMES:
- if section != "globals":
- rtcalls += "def _runtime_%s_%s():\n" % (location_str, section)
- sectiontext = self.GetSection(section).strip()
- sectiontext.replace('\n', '\n ') + "\n\n"
- globalsection = self.GetSection("globals")
-## Code generated by Beremiz python mixin confnode
-## Code for PLC global variable access
-from targets.typemapping import TypeTranslator
-_%(pyextname)sGlobalsDesc = []
-__ext_name__ = "%(pyextname)s"
-PLCGlobalsDesc.append(( "%(pyextname)s" , _%(pyextname)sGlobalsDesc ))
-## User code in "global" scope
-## Beremiz python runtime calls
- # 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'))
- # C code for safe global variables access
-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;
- 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);
- 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
- 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.
- * Code generated by Beremiz py_ext confnode
- * for safe global variables access
-#include "iec_types_all.h"
-/* User variables reference */
-/* Beremiz confnode functions */
-int __init_%(location_str)s(int argc,char **argv){
+from LPCArch import PLC_module, SetLPCArch +from Beremiz import BeremizIDELauncher -void __cleanup_%(location_str)s(void){
-void __retrieve_%(location_str)s(void){
-void __publish_%(location_str)s(void){
- Gen_PyCfile_path = os.path.join(buildpath, "PyCFile_%s.c" % location_str)
- pycfile = open(Gen_PyCfile_path, 'w')
- pycfile.write(PyCFileContent)
- matiec_CFLAGS = '"-I%s"' % os.path.abspath(
- self.GetCTRoot().GetIECLibPath())
- return ([(Gen_PyCfile_path, matiec_CFLAGS)],
- ("runtime_%s.py" % location_str, file(runtimefile_path, "rb")))
-PythonFileCTNMixin.CTNGenerate_C = CTNGenerate_C
-def ResetSearchResults(self):
- self.SearchParams = None
- self.SearchResults = None
- self.VariableSearchResults = []
- self.CurrentFindHighlight = None
-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)
- ERROR_HIGHLIGHT: STC_CODE_ERROR,
- SEARCH_RESULT_HIGHLIGHT: STC_CODE_SEARCH_RESULT,
-def FindVariable(self, direction, search_params, variables):
- if self.SearchParams != search_params:
- 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()
- if search_value in value:
- self.VariableSearchResults.append((row, col))
- if len(self.VariableSearchResults) > 0:
- (r, c) = self.VariableSearchResults[self.index]
- variables.VariablesGrid.SetCellBackgroundColour(r, c, SEARCH_RESULT_HIGHLIGHT[1])
- 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):
- from xml.dom import minidom
- dir_list = next(os.walk(self.ProjectPath))[1]
- if dir not in ["build", "CanOpen@CanOpen", "project_files"]:
- path = os.path.join(self.ProjectPath, dir, 'pyfile.xml')
- if os.path.exists(path):
- pyfile = minidom.parse(path)
- variablelist = pyfile.getElementsByTagName('variable')
- if criteria["find_pattern"] in s.attributes['name'].value:
-PLCControler.SearchInPyfile = SearchInPyfile
-def OnSearchInProjectMenu(self, event):
- dialog = SearchInProjectDialog(self)
- if dialog.ShowModal() == wx.ID_OK:
- criteria = dialog.GetCriteria()
- 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):
- 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"])])
- 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():
- item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
- 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))
-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"])
- root = self.SearchResultsTree.GetRootItem()
- self.SearchResultsTree.AppendItem(root, name[0], image=self.TreeImageDict["wx_glade"])
- 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.ElementsOrder = []
- self.SearchResults = {}
- self.PySearchResults = []
-SearchResultPanel.ResetSearchResults = ResetSearchResults
-def GetPythonTextCtrlDClickFunction(self, item):
- for type in self.ParentWindow.CTR.Children.values():
- if name.BaseParams.attrib['Name'] == item:
- selected = self.ParentWindow.TabsOpened.GetSelection()
- 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)
-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
- 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): + BeremizIDELauncher.__init__(self) + self.extensions = [os.path.join(_lpcmanager_path, "LPCExtension.py")] + "LPCProjectController", - 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)
- 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)
- for idx, (name, label) in enumerate([('XScale', _('Horizontal:')),
- ('YScale', _('Vertical:'))]):
- 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,
- 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
- 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)
- self.dialog = WampOptionsEditor(self.Parent.Parent, options, desc)
- answer = self.dialog.ShowModal()
- opt,OnChange,value,description = self.dialog.GetOptions()
- self.grid.SetCellValue(event.GetRow(), event.GetCol(), str(opt))
- self.grid.SetCellValue(event.GetRow(), event.GetCol()-1, value)
- self.grid.SetCellValue(event.GetRow(), event.GetCol()-2, description)
- self.Parent.RefreshModel()
-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.
- for row in range(self.GetNumberRows()):
- for col in range(self.GetNumberCols()):
- 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":
- 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()
-# self.GrandParent.CTR.logger.write_warning("Can not reset log messages!\n")
-# self.ResetLogMessages()
-# 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):
- return defaultGenerateNewName(self, tagname, name, format, start_idx=0, exclude={}, debug=False)
- while name is None or names.get(name.upper(), False):
-PLCControler.GenerateNewName = newGenerateNewName
-from canfestival import RootClass as CanOpenRootClass
-from canfestival.canfestival import _SlaveCTN, _NodeListCTN, NodeManager
-from canfestival.NetworkEditor import NetworkEditor
-from canfestival.SlaveEditor import SlaveEditor
-# havecanfestival = False
-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',
- 'other': 'Comic Sans MS',
- faces = {'times': 'Times',
- 'other': 'new century schoolbook',
-# ConfTreeNodeEditor.SHOW_BASE_PARAMS = False
-# -------------------------------------------------------------------------------
-# CANFESTIVAL CONFNODE HACK
-# -------------------------------------------------------------------------------
-from canfestival import canfestival
-defaultGetCFLAGS = canfestival.local_canfestival_config.getCFLAGS
-defaultGetLDFLAGS = canfestival.local_canfestival_config.getLDFLAGS
- return str(defaultGetCFLAGS(*args))
- return str(defaultGetLDFLAGS(*args))
-canfestival.local_canfestival_config.getCFLAGS = getCFLAGS
-canfestival.local_canfestival_config.getLDFLAGS = getLDFLAGS
-import LPCBus as LPCBus_mod
- LPCBus_mod.LPCarch = "MC9"
- LPCBus_mod.LPCarch = arch
-# -------------------------------------------------------------------------------
-# LPC CanFestival ConfNode Class
-# -------------------------------------------------------------------------------
- "CAN_Baudrate": "125K",
-class LPCSlaveEditor(SlaveEditor):
- # SHOW_BASE_PARAMS = False
-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: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:restriction base="xsd:integer">
- <xsd:minInclusive value="1"/>
- <xsd:maxInclusive value="99"/>
- EditorType = LPCSlaveEditor
+ print("\nUsage of LPCManager.py :") + print("\n %s Projectpath Buildpath port arch\n" % sys.argv[0])
- # TODO change netname when name change
- NodeManager.__init__(self)
- odfilepath = self.GetSlaveODPath()
- if (os.path.isfile(odfilepath)):
- self.OpenFileInCurrent(odfilepath)
- self.CreateNewNode("SlaveNode", # Name - will be changed at build time
- 0x00, # NodeID - will be changed at build time
- def GetCanDevice(self):
- return str(self.BaseParams.getIEC_Channel())
- {"bitmap": "NetworkEdit",
- "name": _("Edit slave"),
- "tooltip": _("Edit CanOpen slave with ObjdictEdit"),
- "method": "_OpenView"},
- ] + _SlaveCTN.ConfNodeMethods
-class LPCNetworkEditor(NetworkEditor):
- # SHOW_BASE_PARAMS = False
-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: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"/>
- EditorType = LPCNetworkEditor
- def GetCanDevice(self):
- return str(self.BaseParams.getIEC_Channel())
- {"bitmap": "NetworkEdit",
- "name": _("Edit network"),
- "tooltip": _("Edit CanOpen Network with NetworkEdit"),
- "method": "_OpenView"},
- ] + _NodeListCTN.ConfNodeMethods
-class LPCCanOpen(CanOpenRootClass):
- CTNChildrenTypes = [("CanOpenNode", LPCCanOpenMaster, "CanOpen Master"),
- ("CanOpenSlave", LPCCanOpenSlave, "CanOpen Slave")]
- def GetCanDriver(self):
- 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)
-# -------------------------------------------------------------------------------
-# 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):
- mycopytree(srcpath, dstpath)
- elif os.path.isfile(srcpath):
- shutil.copy2(srcpath, dstpath)
-[SIMULATION_MODE, TRANSFER_MODE] = range(2)
- class LPCProjectNodeEditor(ProjectNodeEditor):
- class LPCProjectNodeEditor(ProjectNodeEditor):
- ENABLE_REQUIRED = False
+ def ProcessCommandLineArgs(self): + # Command line arguments parsing + opts, args = getopt.getopt(sys.argv[1:], "h", ["help"]) + except getopt.GetoptError: + # print help information and exit:
- "tooltip": _("Simulate PLC"),
- "method": "_Simulate"},
- "tooltip": _("Start PLC"),
- "tooltip": _("Stop Running PLC"),
- "tooltip": _("Build project into build folder"),
- "tooltip": _("Clean project build folder"),
- "tooltip": _("Transfer PLC"),
- "method": "_Transfer"},
- "Started": [("_Simulate", False),
- "Stopped": [("_Simulate", False),
- "Connected": [("_Simulate", "not simulating"),
- ("_Stop", True if arch in PLC_module else "simulating"),
- "Disconnected": [("_Simulate", "not simulating"),
- ("_Stop", False if arch in PLC_module else "simulating"),
- "Empty" :[("_Simulate", "not simulating"),
- "tooltip": _("Connect to the target PLC"),
- {"bitmap": "Disconnect",
- "name": _("Disconnect"),
- "tooltip": _("Disconnect from PLC"),
- "method": "_Disconnect"},
- "tooltip": _("Update the PLC firmware"),
- "method": "_UpdateFw"},
- _MethodFromPLCState["Disconnected"] += [("_Connect", True),
- ("_Disconnect", False)]
- _MethodFromPLCState["Connected"] += [("_Connect", False),
-class LPCProjectController(ProjectController):
- StatusMethods = _StatusMethods
- EditorType = LPCProjectNodeEditor
- def __init__(self, frame, logger, buildpath):
- self.OrigBuildPath = buildpath
- ProjectController.__init__(self, frame, logger)
- self.CTNChildrenTypes += [("LPCBus", LPCBus, "LPC bus"), ("CanOpen", LPCCanOpen, "CanOpen bus")]
- self.CTNChildrenTypes += [("LPCBus", LPCBus, "LPC bus")]
- 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
- # Bind mouse double click event on URI_location in Beremiz
- def GetProjectName(self):
- return self.Project.getname()
- def GetDefaultTargetName(self):
- if self.CurrentMode == SIMULATION_MODE:
- return ProjectController.GetDefaultTargetName(self)
- target = ProjectController.GetTarget(self)
- if self.CurrentMode != SIMULATION_MODE and arch not in PLC_module:
- target.getcontent().setBuildPath(self.BuildPath)
- 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
- return ProjectController._getBuildPath(self)
- # MD5 = self.GetLastBuildMD5()
- 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')
- self.logger.write(_("Export file is successfully created on location: %s\n") % path_export_file)
- self.logger.write(_("Export file is not created because eror: %s\n") % e)
- save = self.ProjectTestModified()
- self.AppFrame._Refresh(TITLE, FILEMENU)
- if self.BuildPath is not None:
- mycopytree(self.OrigBuildPath, self.BuildPath)
- if ProjectController._Build(self):
- 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.OnlineMode != mode:
- if mode not in ["OFF", ""]:
- self.ConnectorPath = path
- uri = "LPC://%s/%s" % (self.OnlineMode, path)
- self.LPCConnector = connectors.ConnectorFactory(uri, self)
- 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:
- self.logger.write_error(_("Connection failed to %s!\n") % uri)
- self.OnlineMode = "OFF"
- self.LPCConnector = None
- self.ConnectorPath = None
- def ApplyOnlineMode(self):
- if self.CurrentMode != SIMULATION_MODE:
- 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 + if o in ("-h", "--help"): - if self.previous_plcstate is not None:
- status = _(self.previous_plcstate)
- 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.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":
- 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)
- # Update a PLCOpenEditor Pou variable name
- def UpdateProjectVariableName(self, old_name, new_name):
- self.Project.updateElementName(old_name, new_name)
- def RemoveProjectVariableByAddress(self, address):
- self.Project.removeVariableByAddress(address)
- def RemoveProjectVariableByFilter(self, leading):
- self.Project.removeVariableByFilter(leading)
- def AddProjectDefaultConfiguration(self, config_name="config", res_name="resource1"):
- ProjectController.AddProjectDefaultConfiguration(self, config_name, res_name)
- self.SetEditedResourceInfos(
- self.ComputeConfigurationResourceName(config_name, res_name),
- "Triggering": "Cyclic",
- 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):
- result = self.OpenXMLFile(plc_file)
- self.CreateNewProject({"companyName": "",
- if len(self.GetProjectConfigNames()) == 0:
- self.AddProjectDefaultConfiguration()
- # Change XSD into class members
- self._AddParamsMembers()
- # 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()
- # Load and init all the children
- canopen_child = self.GetChildByName("CanOpen")
- if havecanfestival and canopen_child is None:
- canopen = self.CTNAddChild("CanOpen", "CanOpen", 0)
- canopen.CTNRequestSave()
- elif not havecanfestival and canopen_child is not None:
- canopen_child.CTNRemove()
- if self.CTNTestModified():
- if wx.GetApp() is None:
- self.RefreshConfNodesBlockLists()
- wx.CallAfter(self.RefreshConfNodesBlockLists)
- self.SetParamsAttribute('BeremizRoot.TargetType', 'MC9')
- 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 val.endswith("simulating"):
- if val.startswith("not"):
- ProjectController.ShowMethod(self, name, val)
- def UpdateMethodsFromPLCStatus(self):
- simulating = self.CurrentMode == SIMULATION_MODE
- if self.OnlineMode == "OFF":
- status, log_count = self._connector.GetPLCstatus()
- self.UpdatePLCLog(log_count)
- status = "Disconnected"
- elif self.OnlineMode == "BOOTLOADER":
- if self._connector is not None:
- status, log_count = self._connector.GetPLCstatus()
- if status == "Disconnected":
- self._SetConnector(None, False)
- self.UpdatePLCLog(log_count)
- status = "Disconnected"
- if self.previous_plcstate != status or self.previous_mode != self.CurrentMode:
- for args in _MethodFromPLCState.get(status, []):
- self.previous_plcstate = status
- self.previous_mode = self.CurrentMode
- if self.AppFrame is not None:
- self.AppFrame.RefreshStatusToolBar()
- connection_text = _("Connected to: ")
- connection_text += _("Simulation")
- if status == "Disconnected":
- self.AppFrame.ConnectionStatusBar.SetStatusText(_(status), 1)
- self.AppFrame.ConnectionStatusBar.SetStatusText('', 2)
- self.AppFrame.ConnectionStatusBar.SetStatusText(connection_text, 1)
- self.AppFrame.ConnectionStatusBar.SetStatusText(status_text, 2)
- connection_text += " (%s)"
- connection_text += "%s"
- self.AppFrame.ConnectionStatusBar.SetStatusText(connection_text % self.ConnectorPath, 1)
- self.AppFrame.ConnectionStatusBar.SetStatusText(status_text % _(status), 2)
- 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 *name = &beremiz_##name;
-#include "LOCATED_VARIABLES.h"
- def Generate_lpc_retain_array_sim(self):
- Support for retain array in Simulation
- return """/* Support for retain array */
-#define USER_RETAIN_ARRAY_SIZE 2000
-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((0<=INDEX) && (INDEX<USER_RETAIN_ARRAY_SIZE) && (0<=COLUMN) && (COLUMN<NUM_OF_COLS))
- return retainArray[INDEX][COLUMN];
-unsigned char __SetRetainData(unsigned char WRITE, unsigned int INDEX, unsigned int WORD1, unsigned int WORD2, unsigned int WORD3)
- if((0<=INDEX) && (INDEX<USER_RETAIN_ARRAY_SIZE))
- retainArray[INDEX][0] = WORD1;
- retainArray[INDEX][1] = WORD2;
- retainArray[INDEX][2] = WORD3;
-unsigned char __FindRetainData(unsigned char SEARCH, unsigned int START_IDX, unsigned int END_IDX, unsigned int WORD1, unsigned int WORD2, unsigned int WORD3)
- 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 = USER_RETAIN_ARRAY_SIZE; /* Data not found => return index that is out of array bounds */
-/* Since Beremiz debugger doesn't like pointer-by-reference stuff or global varibles, separate function is a must */
-unsigned char __GetReadStatus(unsigned char dummy)
-unsigned int __GetFoundIndex(unsigned char dummy)
- Method called by user to Simulate PLC
- self._SetConnector(connectors.ConnectorFactory(uri, self))
- 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:
- self.logger.write_error(_("Connection failed to %s!\n") % uri)
- self.CurrentMode = SIMULATION_MODE
- buildpath = self._getBuildPath()
- # Eventually create build dir
- if not os.path.exists(buildpath):
- # Generate SoftPLC IEC code
- IECGenRes = self._Generate_SoftPLC()
+ self.projectOpen = args[0] + self.buildpath = args[1] + self.port = int(args[2]) - # If IEC code gen fail, bail out.
- self.logger.write_error(_("IEC-61131-3 code generation failed !\n"))
- # 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
- self.LocationCFilesAndCFLAGS = [(self.GetCurrentLocation(), CTNCFilesAndCFLAGS, DoCalls)]
- self.LocationCFilesAndCFLAGS = []
- # confnode asks for some LDFLAGS
- # LDFLAGS can be either string
- if type(CTNLDFLAGS) == type(str()):
- self.LDFLAGS = [CTNLDFLAGS]
- elif type(CTNLDFLAGS) == type(list()):
- self.LDFLAGS = CTNLDFLAGS[:]
- # 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 [
- (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")]:
- 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))
- self.logger.write_error(name + _(" generation failed !\n"))
- self.logger.write_error(traceback.format_exc())
- # Get simulation builder
- builder = self.GetBuilder()
- self.logger.write_error(_("Fatal : cannot get builder.\n"))
- if not builder.build():
- self.logger.write_error(_("C Build failed.\n"))
- self.logger.write_error(_("C Build crashed !\n"))
- self.logger.write_error(traceback.format_exc())
- data = builder.GetBinaryCode()
- 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"))
- self.logger.write_error(_("Transfer failed\n"))
- 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)
- ProjectController._Stop(self)
- if self.CurrentMode == SIMULATION_MODE:
- def CompareLocalAndRemotePLC(self):
- # if self.LPCConnector is None:
- if self._connector is None:
- # 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]))
- 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"))
- self.logger.write_error(_("Build directory already clean\n"))
- self.ShowMethod("_showIECcode", False)
- self.EnableMethod("_Clean", False)
- self.CompareLocalAndRemotePLC()
+ # overload with exacltly same code, but this is intended. + # we want extensions to use globals of this module, not Beremiz.py
- 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:
- ProjectController._Transfer(self)
- 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.logger.write(_("Resetting PLC\n"))
- # self.StatusTimer.Stop()
- self.LPCConnector.ResetPLC()
- self.AbortTransferTimer.Start(milliseconds=5000, oneShot=True)
- 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
- old_DebugThreadProc = ProjectController.DebugThreadProc
- def LPCManager_DebugThreadProc(self, checking=False):
- state, ls = self._connector.GetTraceVariables()
- while state == "Stopped":
- state, ls = self._connector.GetTraceVariables()
- self.old_DebugThreadProc()
- def _connect_debug(self, checking = False):
- self.previous_plcstate = None
- 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()
- if self.GetIECProgramsAndVariables():
- self._connector.StartPLC()
- self.logger.write(_("Starting PLC\n"))
- self._connect_debug(True)
- self.logger.write_error(_("Couldn't start PLC !\n"))
- self.UpdateMethodsFromPLCStatus()
- self._SetConnector(None)
- 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"))
- 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()
- if answer == wx.ID_CANCEL:
- self.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- 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
- self.logger.write(_("Firmware image file: %s\n") % imageFilePath)
- self.logger.write(_("Firmware update type: Linux kernel image\n"))
- self.logger.write(_("Firmware update type: Linux DTB image\n"))
- self.logger.write(_("Firmware update type: Root file system image\n"))
- self.logger.write_error(_("Unknown firmware update type!\n"))
- self.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- 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
- 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)
- # 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()
- # 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
+ CMDpipe = self.StdoutPseudoFile.StdoutPseudoFile(self.port, self.debug) - # Get connector from uri
- self._SetConnector(connectors.ConnectorFactory(uri, self))
- 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
- # Did connection success ?
- if self._connector is None:
- self.logger.write_error(_("Connection failed to %s!\n") % uri)
- self.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- 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.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- self.AppFrame.Refresh()
- # Lauch the firmaware update on the remote PLC
- updater = HostFirmwareUpdater(self._connector, imageFilePath, updateType, chunksSize, reboot, self.logger)
- self.logger.write_error(str(e) + "\n")
- self.logger.write_error(_("Firmware update canceled!\n"))
- self.firmawreUpadateIsRunning = False
- self.firmawreUpadateIsRunning = False
-# -------------------------------------------------------------------------------
-# -------------------------------------------------------------------------------
-class LPCBeremiz(Beremiz):
- def _init_coll_FileMenu_Items(self, parent):
- config = wx.ConfigBase.Get()
- export = str(config.Read("Exporter"))
- config.Write("Exporter", '0')
- 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()
- 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)
- 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):
- # loading_splash = splash.SmartehScreenSplash(self, bitmap=GetPath(splash.SPLASH_FN), signal=signal_init)
- # thread = Thread(target=loading_splash.Show)
- def OnCloseFrame(self, event):
- if self.CheckSaveBeforeClosing(_("Close Application")):
- 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"))
- os.kill(int(wxGladePid), signal.SIGTERM)
- config.Write("BeremizRoot.wxGlade", str(wxGladePid))
- lpcberemiz_cmd.Log.write("Closed\n")
- def RefreshTitle(self):
- if self.CTR is not None:
- projectname = self.CTR.GetProjectName()
- if self.CTR.ProjectTestModified():
- projectname = "~%s~" % projectname
- self.SetTitle("%s - %s" % (name, projectname))
+ 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()
- graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer)
- if self.TabsOpened.GetPageCount() > 0:
- self.FileMenu.Enable(wx.ID_CLOSE, True)
- self.FileMenu.Enable(wx.ID_PREVIEW, True)
- self.FileMenu.Enable(wx.ID_PRINT, True)
- MenuToolBar.EnableTool(wx.ID_PRINT, True)
- 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_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) + CMDpipe.write("Error: Invalid project directory", result) - 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()
- 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)
- Beremiz.RefreshAll(self)
- # Remove taskbar icon when simulating
- def StartLocalRuntime(self, taskbaricon=True):
- return Beremiz.StartLocalRuntime(self, taskbaricon=False)
- def __init__(self, port):
- self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.socket.connect(('localhost', port))
- idx = self.Buffer.find("\n")
- text = self.socket.recv(2048)
- idx = self.Buffer.find("\n")
- line = self.Buffer[:idx + 1]
- self.Buffer = self.Buffer[idx + 1:]
- print "command >" + line
- """ Base class for file like objects to facilitate StdOut for the Shell."""
- def write(self, s, style=None):
- self.socket.send(s.encode('utf8'))
- def writeyield(self, s):
- def write_warning(self, s):
- def write_error(self, s):
-from threading import Thread, Timer, Semaphore, Lock
-wx_eval_lock = Semaphore(0)
-def wx_evaluator(callable, *args, **kwargs):
- eval_res = callable(*args, **kwargs)
-def evaluator(callable, *args, **kwargs):
- wx.CallAfter(wx_evaluator, callable, *args, **kwargs)
-# Command log for debug, for viewing from wxInspector
- __builtins__.cmdlog = []
-class LPCBeremiz_Cmd(cmd.Cmd):
- def __init__(self, CTR, Log):
- cmd.Cmd.__init__(self, stdin=Log, stdout=Log)
- self.use_rawinput = False
- self.restore_last_state = False
- 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 do_EOF(self, line):
+ CMDpipe.write("Error: No such file or directory") - def Show(self, loading=False):
- self.CTR.SetAppFrame(frame, frame.Log)
- self.CTR.UpdateMethodsFromPLCStatus()
- self.restore_last_state = True
- if self.restore_last_state:
- self.restore_last_state = False
- frame.RestoreLastState()
- frame._Refresh(TITLE, PROJECTTREE, POUINSTANCEVARIABLESPANEL, FILEMENU, EDITMENU)
- self.CTR.ResetAppFrame(self.Log)
- def SetProjectProperties(self, projectname, productname, productversion, companyname):
- "projectName": projectname,
- "productName": productname,
- "productVersion": productversion,
- "companyName": companyname}
- self.CTR.SetProjectProperties(properties=new_properties, buffer=False)
- def SetOnlineMode(self, mode, path=None):
- self.CTR.SetOnlineMode(mode, path)
- 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)
- return "Error: Unable to create bus\n"
- def RenameBus(self, iec_channel, name):
- bus = self.CTR.GetChildByIECLocation((iec_channel,))
- 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)
+ lpcberemiz_cmd = self.LPCCommand.LPCCommand(self, CTR, CMDpipe) - def ChangeBusIECChannel(self, old_iec_channel, new_iec_channel):
- bus = self.CTR.GetChildByIECLocation((old_iec_channel,))
- 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),
- self.CTR.UpdateProjectVariableLocation(
- bus.BaseParams.setIEC_Channel(new_iec_channel)
- def RemoveBus(self, iec_channel):
- bus = self.CTR.GetChildByIECLocation((iec_channel,))
- return "Error: No bus found\n"
- self.CTR.RemoveProjectVariableByFilter(str(iec_channel))
- self.CTR.Children["LPCBus"].remove(bus)
- def AddModule(self, parent, iec_channel, name, icode, icon=None):
- module = self.CTR.GetChildByIECLocation(parent)
- 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,
- def RenameModule(self, iec_location, name):
- module = self.CTR.GetChildByIECLocation(iec_location)
- return "Error: No module found\n"
- parent = self.CTR.GetChildByIECLocation(iec_location[:-1])
- 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
- def ChangeModuleIECChannel(self, old_iec_location, new_iec_channel):
- module = self.CTR.GetChildByIECLocation(old_iec_location)
- return "Error: No module found\n"
- parent = self.CTR.GetChildByIECLocation(old_iec_location[:-1])
- 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
- def ChangeModuleInitCode(self, iec_location, icode):
- module = self.CTR.GetChildByIECLocation(iec_location)
- return "Error: No module found\n"
- def RemoveModule(self, parent, iec_channel):
- module = self.CTR.GetChildByIECLocation(parent)
- return "Error: No parent found\n"
- child = GetModuleBySomething(module, "IEC_Channel", (iec_channel,))
- return "Error: No module found\n"
- self.CTR.RemoveProjectVariableByFilter(".".join(map(str, parent + (iec_channel,))))
- RemoveModuleChild(module, child)
+ cmd_thread = Thread(target=lpcberemiz_cmd.cmdloop) + # TODO: join() when exiting - def StartGroup(self, parent, name, icon=None):
- module = self.CTR.GetChildByIECLocation(parent)
- 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,
- def AddVariable(self, parent, location, name, direction, type, rcode, pcode, description=""):
- module = self.CTR.GetChildByIECLocation(parent)
- 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,
- "type": LOCATION_TYPES[direction],
- "description": description,
- def ChangeVariableParams(self, parent, location, new_name, new_direction, new_type, new_rcode, new_pcode,
- module = self.CTR.GetChildByIECLocation(parent)
- return "Error: No parent found\n"
- for child in GetModuleChildren(module):
- if child["location"] == location and child["type"] == LOCATION_TYPES[new_direction]:
- elif child["name"] == new_name:
- return "Error: A variable named %s already exists\n" % new_name
- 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
- def RemoveVariable(self, parent, location, direction):
- module = self.CTR.GetChildByIECLocation(parent)
- return "Error: No parent found\n"
- child = GetModuleVariable(module, location, direction)
- 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)
- 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")
- for num, arg in enumerate(args_toks):
- args.extend(stripped.split(" "))
- if opt == 0 and len(args) != arg_number:
- elif len(args) > arg_number:
- elif len(args) < arg_number - opt:
- number = arg_number - opt
- self.Log.write("Error: No argument%s expected\n" % extra)
- self.Log.write("Error: 1 argument%s expected\n" % extra)
- self.Log.write("Error: %d arguments%s expected\n" % (number, extra))
- for num, arg in enumerate(args):
- args[num] = arg_types[num](arg)
- self.Log.write("Error: Invalid value for argument %d\n" % (num + 1))
+ def CreateApplication(self): + BeremizIDELauncher.CreateApplication(self) - func = getattr(self, function)
- res = evaluator(func, *args)
- cmdlog.append((function, line, res))
- if len(cmdlog) > 100: # prevent debug log to grow too much
- if isinstance(res, (StringType, UnicodeType)):
-def CmdThreadProc(CTR, Log):
- for function, (arg_types, opt) in {"Exit": ([], 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)
- Log.write("Error: Invalid project directory", result)
- Log.write("Error: No such file or directory")
- cmd_thread = Thread(target=CmdThreadProc, args=[CTR, Log])
- # Install a exception handle for bug reports
- import util.ExceptionHandler
- util.ExceptionHandler.AddExceptHook(version.app_version)
- frame = LPCBeremiz(None, ctr=CTR, debug=True)
+ lpcmanager = LPCManagerLauncher() --- /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 @@
+from __future__ import absolute_import +from ProjectController import ProjectController +from LPCArch import PLC_module +from FirmwareUpdateDialog import FirmwareUpdateDialog +from dialogs import DiscoveryDialog +from HostFirmwareUpdater import HostFirmwareUpdater + "tooltip": _("Update the PLC firmware"), +class LPCProjectController(ProjectController): + StatusMethods = ProjectController.StatusMethods + LPCStatusMethods + def __init__(self, frame, logger, buildpath, 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() + Zip project files for use in xEye + 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') + self.logger.write(_("xEye export file created at: %s\n") % output_file_path) + AutoSave before regular build, and zip for xEye after + if self.ProjectTestModified(): + self.AppFrame.RefreshAfterSave() + result = ProjectController._Build(self) + def SetProjectName(self, name): + return self.Project.setname(name) + def SetOnlineMode(self, mode, path=None): + # SetOnlineMode is only for MC8 + # Update a PLCOpenEditor Pou variable location + def UpdateProjectVariableLocation(self, old_leading, new_leading): + self.Project.updateElementAddress(old_leading, new_leading) + # Update a PLCOpenEditor Pou variable name + def UpdateProjectVariableName(self, old_name, new_name): + self.Project.updateElementName(old_name, new_name) + def RemoveProjectVariableByAddress(self, address): + self.Project.removeVariableByAddress(address) + def RemoveProjectVariableByFilter(self, leading): + self.Project.removeVariableByFilter(leading) + def AddProjectDefaultConfiguration(self, config_name="config", res_name="resource1"): + ProjectController.AddProjectDefaultConfiguration(self, config_name, res_name) + self.SetEditedResourceInfos( + self.ComputeConfigurationResourceName(config_name, res_name), + "Triggering": "Cyclic", + 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) + ProjectController.LoadProject(self, ProjectPath, BuildPath) + canopen_child = self.GetChildByName("CanOpen") + if canopen_child is None: + canopen = self.CTNAddChild("CanOpen", "CanOpen", 0) + canopen.CTNRequestSave() + if self.CTNTestModified(): + self.RefreshConfNodesBlockLists() + if self.arch in PLC_module: + self.SetParamsAttribute('BeremizRoot.TargetType', 'MC9') + 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")) + 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() + if answer == wx.ID_CANCEL: + self.logger.write_error(_("Firmware update canceled!\n")) + self.firmwareUpadateIsRunning = False + 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 + self.logger.write(_("Firmware image file: %s\n") % imageFilePath) + self.logger.write(_("Firmware update type: Linux kernel image\n")) + self.logger.write(_("Firmware update type: Linux DTB image\n")) + self.logger.write(_("Firmware update type: Root file system image\n")) + self.logger.write_error(_("Unknown firmware update type!\n")) + self.logger.write_error(_("Firmware update canceled!\n")) + self.firmwareUpadateIsRunning = False + 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 + 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) + # 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() + # 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 + # Get connector from uri + self._SetConnector(connectors.ConnectorFactory(uri, self)) + 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 + # Did connection success ? + if self._connector is None: + self.logger.write_error(_("Connection failed to %s!\n") % uri) + self.logger.write_error(_("Firmware update canceled!\n")) + self.firmwareUpadateIsRunning = False + 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.logger.write_error(_("Firmware update canceled!\n")) + self.firmwareUpadateIsRunning = False + self.AppFrame.Refresh() + # Lauch the firmaware update on the remote PLC + updater = HostFirmwareUpdater(self._connector, imageFilePath, updateType, chunksSize, reboot, self.logger) + self.logger.write_error(str(e) + "\n") + self.logger.write_error(_("Firmware update canceled!\n")) + self.firmwareUpadateIsRunning = False + self.firmwareUpadateIsRunning = False --- 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 @@
if __name__ == "__main__":
- __builtins__.BMZ_DBG = True
TestConnection = LPCBootProto(2,115200,1200)
mystr=file("fw.bin").read()
--- 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 @@
def __init__(self, port, rate, timeout):
self._serialPort = serial.Serial( port, rate, timeout = timeout, writeTimeout = timeout )
--- 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
-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"
- def CustomFunctionCall(self, funcname, args=None):
- member = self.__dict__.get(funcname, 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
- RemoteMWControllerProxy = Pyro.core.getAttrProxyForURI(schemename + "://" + location + "/MWController")
- pyro_connector = oldPYRO_connector_factory(uri, confnodesroot)
- pyro_connector.RemoteMWControllerProxy = RemoteMWControllerProxy
- pyro_connector.CustomFunctionCall = CustomFunctionCall
-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
-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
-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!")}
-_WampSessionEvent = Event()
-class MWWampSession(wamp.ApplicationSession):
- self.join(u"Automation", [u"wampcra"], USER)
- print "CRA checking init ..."
- def onJoin(self, details):
- global _WampSession, _WampSessionEvent
- _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')
- raise Exception("don't know how to handle authmethod {}".format(challenge.method))
- def onLeave(self, details):
- global _WampSession, _WampSessionEvent
- _WampSessionEvent.clear()
- 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),
- session_factory = wamp.ApplicationSessionFactory(
- config = component_config)
- session_factory.session = MWWampSession
- # create a WAMP-over-WebSocket transport client factory
- transport_factory = WampWebSocketClientFactory(
- 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)
-def MWWAMP_connector_factory(uri, confnodesroot):
- # def CustomFunctionCall(self, funcname, args=None):
- # member = self.__dict__.get(funcname, None)
- # member = WampSessionProcMapper(funcname)
- # self.__dict__[funcname] = member
- # WAMP.RegisterWampClient = MWRegisterWampClient
- # WAMP.WampSession = MWWampSession
- # wamp_connector = DefalutWAMP_connector_factory(uri, confnodesroot)
- # wamp_connector.CustomFunctionCall = CustomFunctionCall
- # 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
- _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):
- if _WampSession is not None:
- return threads.blockingCallFromThread(
- reactor, _WampSession.call, wampfuncname,
- except TransportLost, e:
- confnodesroot.logger.write_error(_("Connection lost!\n"))
- confnodesroot._SetConnector(None)
- errmess = traceback.format_exc()
- confnodesroot.logger.write_error(errmess + "\n")
- # confnodesroot._SetConnector(None)
- return PLCObjDefaults.get(funcname)
- class WampPLCObjectProxy(object):
- global _WampSessionEvent, _WampConnection
- if not reactor.running:
- Thread(target=ThreadProc).start()
- _WampConnection = threads.blockingCallFromThread(
- reactor, MWRegisterWampClient, realm, ID, url, confnodesroot)
- if not _WampSessionEvent.wait(5):
- _WampConnection = stopConnecting()
- raise Exception, _("WAMP connection timeout")
- _WampConnection.disconnect()
- def __getattr__(self, attrName):
- member = self.__dict__.get(attrName, None)
- member = WampSessionProcMapper(attrName)
- self.__dict__[attrName] = member
- # Try to get the proxy object
- return WampPLCObjectProxy()
- confnodesroot.logger.write_error(_("WAMP connection to '%s' failed.\n") % location)
- confnodesroot.logger.write_error(traceback.format_exc())
-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 @@
+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 +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): + 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): +# class LPCProjectNodeEditor(ProjectNodeEditor): +# ENABLE_REQUIRED = False + "tooltip": _("Simulate PLC"), + "method": "_Simulate"}, + "tooltip": _("Start PLC"), + "tooltip": _("Stop Running PLC"), + "tooltip": _("Build project into build folder"), + "tooltip": _("Clean project build folder"), + "tooltip": _("Transfer PLC"), + "method": "_Transfer"}, + "Started": [("_Simulate", False), + "Stopped": [("_Simulate", False), + "Connected": [("_Simulate", "not simulating"), + ("_Stop", True), # TODO: if arch in PLC_module else "simulating"), + "Disconnected": [("_Simulate", "not simulating"), + ("_Stop", False), # TODO: if arch in PLC_module else "simulating"), + "Empty" :[("_Simulate", "not simulating"), +# TODO # if arch in PLC_module: + "tooltip": _("Connect to the target PLC"), + {"bitmap": "Disconnect", + "name": _("Disconnect"), + "tooltip": _("Disconnect from PLC"), + "method": "_Disconnect"}, + "tooltip": _("Update the PLC firmware"), + "method": "_UpdateFw"}, +_MethodFromPLCState["Disconnected"] += [("_Connect", True), + ("_Disconnect", False)] +_MethodFromPLCState["Connected"] += [("_Connect", False), +class LPCProjectController(ProjectController): + StatusMethods = _StatusMethods + # TODO : re-consider customization for MC8 + # EditorType = LPCProjectNodeEditor + def __init__(self, frame, logger, buildpath, arch): + self.OrigBuildPath = buildpath + ProjectController.__init__(self, frame, logger) + self.CTNChildrenTypes += [("LPCBus", LPCBus, "LPC bus"), ("CanOpen", LPCCanOpen, "CanOpen bus")] + 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 + # Bind mouse double click event on URI_location in Beremiz + def GetProjectName(self): + return self.Project.getname() + def GetDefaultTargetName(self): + if self.CurrentMode == SIMULATION_MODE: + return ProjectController.GetDefaultTargetName(self) + target = ProjectController.GetTarget(self) + if self.CurrentMode != SIMULATION_MODE and self.arch not in PLC_module: + target.getcontent().setBuildPath(self.BuildPath) + 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 + return ProjectController._getBuildPath(self) + # MD5 = self.GetLastBuildMD5() + 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') + self.logger.write(_("Export file is successfully created on location: %s\n") % path_export_file) + self.logger.write(_("Export file is not created because eror: %s\n") % e) + save = self.ProjectTestModified() + self.AppFrame._Refresh(TITLE, FILEMENU) + if self.BuildPath is not None: + mycopytree(self.OrigBuildPath, self.BuildPath) + if ProjectController._Build(self): + 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: + if self.OnlineMode != mode: + if mode not in ["OFF", ""]: + self.ConnectorPath = path + uri = "LPC://%s/%s" % (self.OnlineMode, path) + self.LPCConnector = connectors.ConnectorFactory(uri, self) + 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: + self.logger.write_error(_("Connection failed to %s!\n") % uri) + self.OnlineMode = "OFF" + self.LPCConnector = None + self.ConnectorPath = None + def ApplyOnlineMode(self): + if self.CurrentMode != SIMULATION_MODE: + 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) + 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.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": + 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) + # Update a PLCOpenEditor Pou variable name + def UpdateProjectVariableName(self, old_name, new_name): + self.Project.updateElementName(old_name, new_name) + def RemoveProjectVariableByAddress(self, address): + self.Project.removeVariableByAddress(address) + def RemoveProjectVariableByFilter(self, leading): + self.Project.removeVariableByFilter(leading) + def AddProjectDefaultConfiguration(self, config_name="config", res_name="resource1"): + ProjectController.AddProjectDefaultConfiguration(self, config_name, res_name) + self.SetEditedResourceInfos( + self.ComputeConfigurationResourceName(config_name, res_name), + "Triggering": "Cyclic", + 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): + result = self.OpenXMLFile(plc_file) + self.CreateNewProject({"companyName": "", + if len(self.GetProjectConfigNames()) == 0: + self.AddProjectDefaultConfiguration() + # Change XSD into class members + self._AddParamsMembers() + # 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() + # Load and init all the children + canopen_child = self.GetChildByName("CanOpen") + if canopen_child is None: + canopen = self.CTNAddChild("CanOpen", "CanOpen", 0) + canopen.CTNRequestSave() + if self.CTNTestModified(): + if wx.GetApp() is None: + self.RefreshConfNodesBlockLists() + wx.CallAfter(self.RefreshConfNodesBlockLists) + if self.arch in PLC_module: + self.SetParamsAttribute('BeremizRoot.TargetType', 'MC9') + 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 val.endswith("simulating"): + if val.startswith("not"): + ProjectController.ShowMethod(self, name, val) + def UpdateMethodsFromPLCStatus(self): + simulating = self.CurrentMode == SIMULATION_MODE + if self.OnlineMode == "OFF": + status, log_count = self._connector.GetPLCstatus() + self.UpdatePLCLog(log_count) + status = "Disconnected" + elif self.OnlineMode == "BOOTLOADER": + if self._connector is not None: + status, log_count = self._connector.GetPLCstatus() + if status == "Disconnected": + self._SetConnector(None, False) + self.UpdatePLCLog(log_count) + status = "Disconnected" + if self.previous_plcstate != status or self.previous_mode != self.CurrentMode: + for args in _MethodFromPLCState.get(status, []): + self.previous_plcstate = status + self.previous_mode = self.CurrentMode + if self.AppFrame is not None: + self.AppFrame.RefreshStatusToolBar() + connection_text = _("Connected to: ") + connection_text += _("Simulation") + if status == "Disconnected": + self.AppFrame.ConnectionStatusBar.SetStatusText(_(status), 1) + self.AppFrame.ConnectionStatusBar.SetStatusText('', 2) + self.AppFrame.ConnectionStatusBar.SetStatusText(connection_text, 1) + self.AppFrame.ConnectionStatusBar.SetStatusText(status_text, 2) + connection_text += " (%s)" + connection_text += "%s" + self.AppFrame.ConnectionStatusBar.SetStatusText(connection_text % self.ConnectorPath, 1) + self.AppFrame.ConnectionStatusBar.SetStatusText(status_text % _(status), 2) + 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 *name = &beremiz_##name; +#include "LOCATED_VARIABLES.h" + def Generate_lpc_retain_array_sim(self): + Support for retain array in Simulation + return """/* Support for retain array */ +#define USER_RETAIN_ARRAY_SIZE 2000 +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((0<=INDEX) && (INDEX<USER_RETAIN_ARRAY_SIZE) && (0<=COLUMN) && (COLUMN<NUM_OF_COLS)) + return retainArray[INDEX][COLUMN]; +unsigned char __SetRetainData(unsigned char WRITE, unsigned int INDEX, unsigned int WORD1, unsigned int WORD2, unsigned int WORD3) + if((0<=INDEX) && (INDEX<USER_RETAIN_ARRAY_SIZE)) + retainArray[INDEX][0] = WORD1; + retainArray[INDEX][1] = WORD2; + retainArray[INDEX][2] = WORD3; +unsigned char __FindRetainData(unsigned char SEARCH, unsigned int START_IDX, unsigned int END_IDX, unsigned int WORD1, unsigned int WORD2, unsigned int WORD3) + 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 = USER_RETAIN_ARRAY_SIZE; /* Data not found => return index that is out of array bounds */ +/* Since Beremiz debugger doesn't like pointer-by-reference stuff or global varibles, separate function is a must */ +unsigned char __GetReadStatus(unsigned char dummy) +unsigned int __GetFoundIndex(unsigned char dummy) + Method called by user to Simulate PLC + self._SetConnector(connectors.ConnectorFactory(uri, self)) + 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: + self.logger.write_error(_("Connection failed to %s!\n") % uri) + self.CurrentMode = SIMULATION_MODE + buildpath = self._getBuildPath() + # Eventually create build dir + if not os.path.exists(buildpath): + # Generate SoftPLC IEC code + IECGenRes = self._Generate_SoftPLC() + # If IEC code gen fail, bail out. + self.logger.write_error(_("IEC-61131-3 code generation failed !\n")) + # 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 + self.LocationCFilesAndCFLAGS = [(self.GetCurrentLocation(), CTNCFilesAndCFLAGS, DoCalls)] + self.LocationCFilesAndCFLAGS = [] + # confnode asks for some LDFLAGS + # LDFLAGS can be either string + if type(CTNLDFLAGS) == type(str()): + self.LDFLAGS = [CTNLDFLAGS] + elif type(CTNLDFLAGS) == type(list()): + self.LDFLAGS = CTNLDFLAGS[:] + # 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 [ + (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")]: + 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)) + self.logger.write_error(name + _(" generation failed !\n")) + self.logger.write_error(traceback.format_exc()) + # Get simulation builder + builder = self.GetBuilder() + self.logger.write_error(_("Fatal : cannot get builder.\n")) + if not builder.build(): + self.logger.write_error(_("C Build failed.\n")) + self.logger.write_error(_("C Build crashed !\n")) + self.logger.write_error(traceback.format_exc()) + data = builder.GetBinaryCode() + 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")) + self.logger.write_error(_("Transfer failed\n")) + 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) + ProjectController._Stop(self) + if self.CurrentMode == SIMULATION_MODE: + def CompareLocalAndRemotePLC(self): + # if self.LPCConnector is None: + if self._connector is None: + # 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])) + 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")) + self.logger.write_error(_("Build directory already clean\n")) + self.ShowMethod("_showIECcode", False) + self.EnableMethod("_Clean", False) + self.CompareLocalAndRemotePLC() + 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: + ProjectController._Transfer(self) + 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.logger.write(_("Resetting PLC\n")) + # self.StatusTimer.Stop() + self.LPCConnector.ResetPLC() + self.AbortTransferTimer.Start(milliseconds=5000, oneShot=True) + 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 + 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")) + 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() + if answer == wx.ID_CANCEL: + self.logger.write_error(_("Firmware update canceled!\n")) + self.firmawreUpadateIsRunning = False + 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 + self.logger.write(_("Firmware image file: %s\n") % imageFilePath) + self.logger.write(_("Firmware update type: Linux kernel image\n")) + self.logger.write(_("Firmware update type: Linux DTB image\n")) + self.logger.write(_("Firmware update type: Root file system image\n")) + self.logger.write_error(_("Unknown firmware update type!\n")) + self.logger.write_error(_("Firmware update canceled!\n")) + self.firmawreUpadateIsRunning = False + 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 + 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) + # 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() + # 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 + # Get connector from uri + self._SetConnector(connectors.ConnectorFactory(uri, self)) + 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 + # Did connection success ? + if self._connector is None: + self.logger.write_error(_("Connection failed to %s!\n") % uri) + self.logger.write_error(_("Firmware update canceled!\n")) + self.firmawreUpadateIsRunning = False + 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.logger.write_error(_("Firmware update canceled!\n")) + self.firmawreUpadateIsRunning = False + self.AppFrame.Refresh() + # Lauch the firmaware update on the remote PLC + updater = HostFirmwareUpdater(self._connector, imageFilePath, updateType, chunksSize, reboot, self.logger) + self.logger.write_error(str(e) + "\n") + self.logger.write_error(_("Firmware update canceled!\n")) + self.firmawreUpadateIsRunning = False + self.firmawreUpadateIsRunning = False --- /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 @@
+ def __init__(self, port, debug): + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.connect(('localhost', port)) + idx = self.Buffer.find("\n") + text = self.socket.recv(2048) + idx = self.Buffer.find("\n") + line = self.Buffer[:idx + 1] + self.Buffer = self.Buffer[idx + 1:] + print "command >" + line + """ Base class for file like objects to facilitate StdOut for the Shell.""" + def write(self, s, style=None): + self.socket.send(s.encode('utf8')) + def writeyield(self, s): + def write_warning(self, s): + def write_error(self, s):