# HG changeset patch # User Edouard Tisserant # Date 1368524493 -32400 # Node ID 28f96aa9c070371714d9f726d3036c733b0bdd99 # Parent f794fbff8f024a50af1a34e44ffadb6cff348dfd Rewrote py_ext and wxglade generators in a clean factored way, added C skeleton for python access to PLC global vars diff -r f794fbff8f02 -r 28f96aa9c070 py_ext/PythonFileCTNMixin.py --- a/py_ext/PythonFileCTNMixin.py Tue May 14 00:30:35 2013 +0200 +++ b/py_ext/PythonFileCTNMixin.py Tue May 14 18:41:33 2013 +0900 @@ -46,7 +46,19 @@ def PythonFileName(self): return os.path.join(self.CTNPath(), "py_ext.xml") - def GetSectionsCode(self): + PreSectionsTexts = {} + PostSectionsTexts = {} + def GetSection(self,section): + return self.PreSectionsTexts.get(section,"") + "\n" + \ + getattr(self.CodeFile, section).gettext() + "\n" + \ + self.PostSectionsTexts.get(section,"") + + + def CTNGenerate_C(self, buildpath, locations): + current_location = self.GetCurrentLocation() + # define a unique name for the generated C file + location_str = "_".join(map(lambda x:str(x), current_location)) + # Generate Beremiz python runtime variables code config = self.GetCTRoot().GetProjectConfigNames()[0] @@ -58,23 +70,95 @@ variable.getname(), variable.gettype(), str(variable.getinitial())) - - sections_code = { - "variables": variables_str, - "globals": self.CodeFile.globals.gettext().strip() - } - - # Generate Beremiz python runtime functions code + + # Runtime calls (start, stop, init, and cleanup) + rtcalls = "" for section in self.SECTIONS_NAMES: if section != "globals": - code_object = getattr(self.CodeFile, section) - section_str = "" - lines = code_object.gettext().strip().splitlines() - if len(lines) > 0: - for line in lines: - section_str += " " + line + "\n" - section_str += "\n" - sections_code[section] = section_str - - return sections_code + rtcalls += "def _runtime_%s_%s():\n" % (location_str, section) + sectiontext = self.GetSection(section).strip() + if sectiontext: + rtcalls += ' ' + \ + sectiontext.strip().replace('\n', '\n ')+"\n" + else: + rtcalls += " pass\n\n" + + text = """\ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +## Code generated by Beremiz python mixin confnode +## + +## Code for PLC global variable access +%s + +## User code in "global" scope +%s +## Beremiz python runtime calls +%s + +"""%( # variables + variables_str, + # globals + self.GetSection("globals"), + # Beremiz python runtime functions + rtcalls) + + runtimefile_path = os.path.join(buildpath, + "runtime_%s.py"%location_str) + runtimefile = open(runtimefile_path, 'w') + runtimefile.write(text.encode('utf-8')) + runtimefile.close() + + text = """\ +/* + * Code generated by Beremiz py_ext confnode + * for safe global variables access + */ +#include "iec_types_all.h" +""" + + # Adding variables + text += "/* User variables reference */\n" + for variable in self.CodeFile.variables.variable: + var_infos = { + "name": variable.getname(), + "global": "%s__%s" % (config.upper(), + variable.getname().upper()), + "type": "__IEC_%s_t" % variable.gettype()} + text += "extern %(type)s %(global)s;\n" % var_infos + text += "%(type)s __buffer_%(name)s;\n" % var_infos + text += "\n" + + # Adding Beremiz confnode functions + text += "/* Beremiz confnode functions */\n" + text += "int __init_%s(int argc,char **argv)\n{\n"%location_str + text += "/*TODO*/\n" + text += " return 0;\n}\n\n" + + text += "void __cleanup_%s(void)\n{\n"%location_str + text += "/*TODO*/\n" + text += "\n}\n\n" + + text += "void __retrieve_%s(void)\n{\n"%location_str + text += "/*TODO*/\n" + text += "\n}\n\n" + + text += "void __publish_%s(void)\n{\n"%location_str + text += "/*TODO*/\n" + text += "\n}\n\n" + + Gen_PyCfile_path = os.path.join(buildpath, "PyCFile_%s.c"%location_str) + pycfile = open(Gen_PyCfile_path,'w') + pycfile.write(text) + pycfile.close() + + matiec_flags = '"-I%s"'%os.path.abspath( + self.GetCTRoot().GetIECLibPath()) + + return ([(Gen_PyCfile_path, matiec_flags)], + "", + False, + ("runtime_%s.py"%location_str, file(runtimefile_path,"rb"))) + diff -r f794fbff8f02 -r 28f96aa9c070 py_ext/py_ext.py --- a/py_ext/py_ext.py Tue May 14 00:30:35 2013 +0200 +++ b/py_ext/py_ext.py Tue May 14 18:41:33 2013 +0900 @@ -8,18 +8,21 @@ def Generate_C(self, buildpath, varlist, IECCFLAGS): - plc_python_filepath = os.path.join(os.path.split(__file__)[0], "plc_python.c") + plc_python_filepath = os.path.join( + os.path.split(__file__)[0], "plc_python.c") plc_python_file = open(plc_python_filepath, 'r') plc_python_code = plc_python_file.read() plc_python_file.close() python_eval_fb_list = [] for v in varlist: - if v["vartype"] == "FB" and v["type"] in ["PYTHON_EVAL","PYTHON_POLL"]: + if v["vartype"] == "FB" and v["type"] in ["PYTHON_EVAL", + "PYTHON_POLL"]: python_eval_fb_list.append(v) python_eval_fb_count = max(1, len(python_eval_fb_list)) # prepare python code - plc_python_code = plc_python_code % { "python_eval_fb_count": python_eval_fb_count } + plc_python_code = plc_python_code % { + "python_eval_fb_count": python_eval_fb_count } Gen_Pythonfile_path = os.path.join(buildpath, "py_ext.c") pythonfile = open(Gen_Pythonfile_path,'w') @@ -33,41 +36,4 @@ def GetIconName(self): return "Pyfile" - def CTNGenerate_C(self, buildpath, locations): - current_location = self.GetCurrentLocation() - # define a unique name for the generated C file - location_str = "_".join(map(lambda x:str(x), current_location)) - - sections_code = self.GetSectionsCode() - - text = "## Code generated by Beremiz python mixin confnode\n\n" - - # Adding variables - text += "## User variables reference\n" - text += sections_code["variables"] - text += "\n" - - # Adding user global variables and routines - text += "## User internal user variables and routines\n" - text += sections_code["globals"] - text += "\n" - - # Adding Beremiz python runtime functions - text += "## Beremiz python runtime functions\n" - for section in self.SECTIONS_NAMES: - if section != "globals": - code_object = getattr(self.CodeFile, section) - text += "def _runtime_%s_%s():\n" % (location_str, section) - section_code = sections_code.get(section) - if section_code: - text += section_code - else: - text += " pass\n\n" - - runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str) - runtimefile = open(runtimefile_path, 'w') - runtimefile.write(text) - runtimefile.close() - - return [], "", False, ("runtime_%s.py"%location_str, file(runtimefile_path,"rb")) diff -r f794fbff8f02 -r 28f96aa9c070 runtime/PLCObject.py --- a/runtime/PLCObject.py Tue May 14 00:30:35 2013 +0200 +++ b/runtime/PLCObject.py Tue May 14 18:41:33 2013 +0900 @@ -264,7 +264,6 @@ self.python_runtime_vars["_runtime_%s"%methodname] = [] self.python_runtime_vars["PLCObject"] = self self.python_runtime_vars["PLCBinary"] = self.PLClibraryHandle - try: for filename in os.listdir(self.workingdir): name, ext = os.path.splitext(filename) @@ -274,7 +273,6 @@ method = self.python_runtime_vars.get("_%s_%s" % (name, methodname), None) if method is not None: self.python_runtime_vars["_runtime_%s"%methodname].append(method) - except: self.LogMessage(0,traceback.format_exc()) raise diff -r f794fbff8f02 -r 28f96aa9c070 wxglade_hmi/wxglade_hmi.py --- a/wxglade_hmi/wxglade_hmi.py Tue May 14 00:30:35 2013 +0200 +++ b/wxglade_hmi/wxglade_hmi.py Tue May 14 18:41:33 2013 +0900 @@ -38,19 +38,6 @@ return PythonFileCTNMixin.OnCTNSave(self, from_project_path) def CTNGenerate_C(self, buildpath, locations): - """ - Return C code generated by iec2c compiler - when _generate_softPLC have been called - @param locations: ignored - @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND - """ - - current_location = self.GetCurrentLocation() - # define a unique name for the generated C file - location_str = "_".join(map(lambda x:str(x), current_location)) - - runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str) - runtimefile = open(runtimefile_path, 'w') hmi_frames = {} @@ -73,65 +60,32 @@ self.launch_wxglade(['-o', wxghmipyfile_path, '-g', 'python', wxgfile_path], wait=True) hmipyfile = open(hmipyfile_path, 'r') - runtimefile.write(hmipyfile.read()) + define_hmi = hmipyfile.read().decode('utf-8') hmipyfile.close() - sections_code = self.GetSectionsCode() + declare_hmi = "\n".join(map(lambda x:"%s = None" % x, + hmi_frames.keys())) + global_hmi = "global "+",".join(hmi_frames.keys()) + init_hmi = "\n".join(map(lambda x: """\ +def OnCloseFrame(evt): + wx.MessageBox(_("Please stop PLC to close")) + +%(name)s = %(class)s(None) +%(name)s.Bind(wx.EVT_CLOSE, OnCloseFrame) +%(name)s.Show() +""" % {"name": x[0], "class": x[1]}, hmi_frames.items())) + cleanup_hmi = "\n".join(map(lambda x:"if %s is not None: %s.Destroy()" % (x,x), hmi_frames.keys())) - # Adding variables - runtimefile.write("## User variables reference\n" + - sections_code["variables"] + "\n") - - # Adding user global variables and routines - runtimefile.write("## User internal user variables and routines\n" + - sections_code["globals"] + "\n") - - for section in ["init", "cleanup"]: - if not sections_code[section]: - sections_code[section] = " pass" - - sections_code.update({ - "location": location_str, - "declare_hmi": "\n".join(map(lambda x:"%s = None" % x, hmi_frames.keys())), - "global_hmi": ",".join(hmi_frames.keys()), - "init_hmi": "\n".join(map(lambda x: """ - %(name)s = %(class)s(None) - %(name)s.Bind(wx.EVT_CLOSE, OnCloseFrame) - %(name)s.Show() -""" % {"name": x[0], "class": x[1]}, - hmi_frames.items())), - "cleanup_hmi": "\n ".join(map(lambda x:"if %s is not None: %s.Destroy()" % (x,x), hmi_frames.keys()))}) - - runtimefile.write(""" -%(declare_hmi)s + self.PreSectionsTexts = { + "globals":define_hmi + declare_hmi, + "start":global_hmi, + "stop":global_hmi + } + self.PostSectionsTexts = { + "start":init_hmi, + } -def _runtime_%(location)s_init(): -%(init)s - -def _runtime_%(location)s_cleanup(): -%(cleanup)s - -def _runtime_%(location)s_start(): - global %(global_hmi)s - -%(start)s - - def OnCloseFrame(evt): - wx.MessageBox(_("Please stop PLC to close")) - - %(init_hmi)s - -def _runtime_%(location)s_stop(): - global %(global_hmi)s - - %(cleanup_hmi)s - -%(stop)s - -""" % sections_code) - runtimefile.close() - - return [], "", False, ("runtime_%s.py"%location_str, file(runtimefile_path,"rb")) + return PythonFileCTNMixin.CTNGenerate_C(self, buildpath, locations) def _editWXGLADE(self): wxg_filename = self._getWXGLADEpath()