Laurent@1315: import os, re Laurent@1315: from lxml import etree Laurent@1315: Laurent@1315: from xmlclass import GenerateParserFromXSD Laurent@1315: Laurent@1315: from CodeFileTreeNode import CodeFile laurent@657: from PythonEditor import PythonEditor laurent@366: Laurent@1097: class PythonFileCTNMixin(CodeFile): Edouard@1436: Laurent@1124: CODEFILE_NAME = "PyFile" Laurent@1124: SECTIONS_NAMES = [ Laurent@1124: "globals", Laurent@1124: "init", Laurent@1124: "cleanup", Laurent@1124: "start", Laurent@1124: "stop"] laurent@657: EditorType = PythonEditor Edouard@1436: laurent@366: def __init__(self): Laurent@1097: CodeFile.__init__(self) Edouard@1436: laurent@366: filepath = self.PythonFileName() Edouard@1436: laurent@366: if os.path.isfile(filepath): Laurent@1315: PythonParser = GenerateParserFromXSD( Edouard@1436: os.path.join(os.path.dirname(__file__), "py_ext_xsd.xsd")) Edouard@1436: laurent@366: xmlfile = open(filepath, 'r') Laurent@1315: pythonfile_xml = xmlfile.read() laurent@366: xmlfile.close() Edouard@1436: Laurent@1315: pythonfile_xml = pythonfile_xml.replace( Edouard@1436: 'xmlns="http://www.w3.org/2001/XMLSchema"', Laurent@1315: 'xmlns:xhtml="http://www.w3.org/1999/xhtml"') Laurent@1315: for cre, repl in [ Laurent@1315: (re.compile("(?)(?:)(?!)"), "]]>")]: Laurent@1315: pythonfile_xml = cre.sub(repl, pythonfile_xml) Edouard@1436: Laurent@1330: try: Laurent@1330: python_code, error = PythonParser.LoadXMLString(pythonfile_xml) Edouard@1436: if error is None: Laurent@1330: self.CodeFile.globals.setanyText(python_code.getanyText()) Laurent@1330: os.remove(filepath) Laurent@1330: self.CreateCodeFileBuffer(False) Laurent@1330: self.OnCTNSave() Laurent@1330: except Exception, exc: Laurent@1330: error = unicode(exc) Edouard@1436: Laurent@1330: if error is not None: Laurent@1330: self.GetCTRoot().logger.write_error( Edouard@1436: _("Couldn't import old %s file.") % self.CTNName()) Edouard@1436: Laurent@1097: def CodeFileName(self): Laurent@1097: return os.path.join(self.CTNPath(), "pyfile.xml") Edouard@1436: laurent@366: def PythonFileName(self): Edouard@721: return os.path.join(self.CTNPath(), "py_ext.xml") laurent@366: Edouard@1132: PreSectionsTexts = {} Edouard@1132: PostSectionsTexts = {} Edouard@1132: def GetSection(self,section): Edouard@1132: return self.PreSectionsTexts.get(section,"") + "\n" + \ Laurent@1315: getattr(self.CodeFile, section).getanyText() + "\n" + \ Edouard@1132: self.PostSectionsTexts.get(section,"") Edouard@1436: Edouard@1132: def CTNGenerate_C(self, buildpath, locations): Edouard@1436: # location string for that CTN Edouard@1436: location_str = "_".join(map(lambda x:str(x), Edouard@1144: self.GetCurrentLocation())) Edouard@1144: configname = self.GetCTRoot().GetProjectConfigNames()[0] Edouard@1436: Edouard@1447: pyextname = self.CTNName() Edouard@1448: varinfos = map(lambda variable : { Edouard@1448: "name": variable.getname(), Edouard@1448: "desc" : repr(variable.getdesc()), Edouard@1448: "onchange" : '"'+variable.getonchange()+"('"+variable.getname()+"')\"" \ Edouard@1448: if variable.getonchange() else "", Edouard@1448: "opts" : repr(variable.getopts()), Edouard@1448: "configname" : configname.upper(), Edouard@1448: "uppername" : variable.getname().upper(), Edouard@1448: "IECtype" : variable.gettype(), Edouard@1448: "pyextname" :pyextname}, Edouard@1448: self.CodeFile.variables.variable) Edouard@1144: # python side PLC global variables access stub Edouard@1144: globalstubs = "\n".join(["""\ Edouard@1144: _%(name)s_ctype, _%(name)s_unpack, _%(name)s_pack = \\ Edouard@1144: TypeTranslator["%(IECtype)s"] Edouard@1144: _PySafeGetPLCGlob_%(name)s = PLCBinary.__SafeGetPLCGlob_%(name)s Edouard@1145: _PySafeGetPLCGlob_%(name)s.restype = None Edouard@1436: _PySafeGetPLCGlob_%(name)s.argtypes = [ctypes.POINTER(_%(name)s_ctype)] Edouard@1144: _PySafeSetPLCGlob_%(name)s = PLCBinary.__SafeSetPLCGlob_%(name)s Edouard@1144: _PySafeSetPLCGlob_%(name)s.restype = None Edouard@1144: _PySafeSetPLCGlob_%(name)s.argtypes = [ctypes.POINTER(_%(name)s_ctype)] Edouard@1448: _%(pyextname)sGlobalsDesc.append(( Edouard@1448: "%(name)s", Edouard@1448: "%(IECtype)s", Edouard@1448: %(desc)s, Edouard@1448: %(opts)s)) Edouard@1448: """ % varinfo for varinfo in varinfos]) Edouard@1132: Edouard@1132: # Runtime calls (start, stop, init, and cleanup) Edouard@1132: rtcalls = "" Laurent@1124: for section in self.SECTIONS_NAMES: Laurent@1124: if section != "globals": Edouard@1132: rtcalls += "def _runtime_%s_%s():\n" % (location_str, section) Edouard@1132: sectiontext = self.GetSection(section).strip() Edouard@1132: if sectiontext: Edouard@1132: rtcalls += ' ' + \ Edouard@1154: sectiontext.replace('\n', '\n ')+"\n\n" Edouard@1132: else: Edouard@1132: rtcalls += " pass\n\n" Edouard@1144: Edouard@1436: globalsection = self.GetSection("globals") Edouard@1436: Edouard@1144: PyFileContent = """\ Edouard@1132: #!/usr/bin/env python Edouard@1132: # -*- coding: utf-8 -*- Edouard@1132: ## Code generated by Beremiz python mixin confnode Edouard@1436: ## Edouard@1436: Edouard@1132: ## Code for PLC global variable access Edouard@1144: from targets.typemapping import TypeTranslator Edouard@1436: import ctypes Edouard@1447: _%(pyextname)sGlobalsDesc = [] Edouard@1447: PLCGlobalsDesc.append(( "_%(pyextname)s" , _%(pyextname)sGlobalsDesc )) Edouard@1144: %(globalstubs)s Edouard@1436: Edouard@1132: ## User code in "global" scope Edouard@1144: %(globalsection)s laurent@366: Edouard@1132: ## Beremiz python runtime calls Edouard@1144: %(rtcalls)s Edouard@1144: Edouard@1144: """ % locals() Edouard@1144: Edouard@1144: # write generated content to python file Edouard@1436: runtimefile_path = os.path.join(buildpath, Edouard@1132: "runtime_%s.py"%location_str) Edouard@1132: runtimefile = open(runtimefile_path, 'w') Edouard@1144: runtimefile.write(PyFileContent.encode('utf-8')) Edouard@1132: runtimefile.close() Edouard@1132: Edouard@1144: # C code for safe global variables access Edouard@1436: Edouard@1144: vardecfmt = """\ Edouard@1154: extern __IEC_%(IECtype)s_t %(configname)s__%(uppername)s; Edouard@1154: IEC_%(IECtype)s __%(name)s_rbuffer = __INIT_%(IECtype)s; Edouard@1154: IEC_%(IECtype)s __%(name)s_wbuffer; Edouard@1144: long __%(name)s_rlock = 0; Edouard@1144: long __%(name)s_wlock = 0; Edouard@1144: int __%(name)s_wbuffer_written = 0; Edouard@1154: void __SafeGetPLCGlob_%(name)s(IEC_%(IECtype)s *pvalue){ Edouard@1144: while(AtomicCompareExchange(&__%(name)s_rlock, 0, 1)); Edouard@1145: *pvalue = __%(name)s_rbuffer; Edouard@1144: AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0); Edouard@1144: } Edouard@1160: void __SafeSetPLCGlob_%(name)s(IEC_%(IECtype)s *value){ Edouard@1144: while(AtomicCompareExchange(&__%(name)s_wlock, 0, 1)); Edouard@1144: __%(name)s_wbuffer = *value; Edouard@1144: __%(name)s_wbuffer_written = 1; Edouard@1144: AtomicCompareExchange((long*)&__%(name)s_wlock, 1, 0); Edouard@1144: } Edouard@1144: Edouard@1144: """ Edouard@1448: Edouard@1448: vardeconchangefmt = """\ Edouard@1448: PYTHON_POLL* __%(name)s_notifier; Edouard@1448: """ Edouard@1448: Edouard@1144: varretfmt = """\ Edouard@1144: if(!AtomicCompareExchange(&__%(name)s_wlock, 0, 1)){ Edouard@1144: if(__%(name)s_wbuffer_written == 1){ Edouard@1144: %(configname)s__%(uppername)s.value = __%(name)s_wbuffer; Edouard@1144: __%(name)s_wbuffer_written = 0; Edouard@1144: } Edouard@1144: AtomicCompareExchange((long*)&__%(name)s_wlock, 1, 0); Edouard@1144: } Edouard@1436: """ Edouard@1144: varpubfmt = """\ Edouard@1144: if(!AtomicCompareExchange(&__%(name)s_rlock, 0, 1)){ Edouard@1448: __%(name)s_rbuffer = __GET_VAR(%(configname)s__%(uppername)s); Edouard@1144: AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0); Edouard@1144: } Edouard@1436: """ Edouard@1144: Edouard@1448: varpubonchangefmt = """\ Edouard@1448: if(!AtomicCompareExchange(&__%(name)s_rlock, 0, 1)){ Edouard@1448: IEC_%(IECtype)s tmp = __GET_VAR(%(configname)s__%(uppername)s); Edouard@1448: if(__%(name)s_rbuffer != tmp){ Edouard@1448: __%(name)s_rbuffer = %(configname)s__%(uppername)s.value; Edouard@1448: PYTHON_POLL_body__(__%(name)s_notifier); Edouard@1448: } Edouard@1448: AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0); Edouard@1448: } Edouard@1448: """ Edouard@1448: varinitonchangefmt = """\ Edouard@1448: __%(name)s_notifier = __GET_GLOBAL_ON%(uppername)sCHANGE(); Edouard@1448: __SET_VAR(__%(name)s_notifier->,TRIG,,__BOOL_LITERAL(TRUE)); Edouard@1448: __SET_VAR(__%(name)s_notifier->,CODE,,__STRING_LITERAL(%(onchangelen)d,%(onchange)s)); Edouard@1448: """ Edouard@1448: vardec = "\n".join([(vardecfmt + vardeconchangefmt Edouard@1448: if varinfo["onchange"] else vardecfmt)% varinfo Edouard@1448: for varinfo in varinfos]) Edouard@1448: varret = "\n".join([varretfmt % varinfo for varinfo in varinfos]) Edouard@1448: varpub = "\n".join([(varpubonchangefmt if varinfo["onchange"] else Edouard@1448: varpubfmt) % varinfo Edouard@1448: for varinfo in varinfos]) Edouard@1448: varinit = "\n".join([varinitonchangefmt % dict( Edouard@1448: onchangelen = len(varinfo["onchange"]),**varinfo) Edouard@1448: for varinfo in varinfos if varinfo["onchange"]]) Edouard@1436: Edouard@1144: PyCFileContent = """\ Edouard@1436: /* Edouard@1436: * Code generated by Beremiz py_ext confnode Edouard@1132: * for safe global variables access Edouard@1132: */ Edouard@1132: #include "iec_types_all.h" Edouard@1448: #include "POUS.h" Edouard@1448: #include "config.h" Edouard@1144: #include "beremiz.h" Edouard@1144: Edouard@1144: /* User variables reference */ Edouard@1144: %(vardec)s Edouard@1144: Edouard@1144: /* Beremiz confnode functions */ Edouard@1144: int __init_%(location_str)s(int argc,char **argv){ Edouard@1448: %(varinit)s Edouard@1144: return 0; Edouard@1144: } Edouard@1144: Edouard@1144: void __cleanup_%(location_str)s(void){ Edouard@1144: } Edouard@1144: Edouard@1144: void __retrieve_%(location_str)s(void){ Edouard@1144: %(varret)s Edouard@1144: } Edouard@1144: Edouard@1144: void __publish_%(location_str)s(void){ Edouard@1144: %(varpub)s Edouard@1144: } Edouard@1144: """ % locals() Edouard@1436: Edouard@1132: Gen_PyCfile_path = os.path.join(buildpath, "PyCFile_%s.c"%location_str) Edouard@1132: pycfile = open(Gen_PyCfile_path,'w') Edouard@1144: pycfile.write(PyCFileContent) Edouard@1132: pycfile.close() Edouard@1436: Edouard@1132: matiec_flags = '"-I%s"'%os.path.abspath( Edouard@1132: self.GetCTRoot().GetIECLibPath()) Edouard@1436: Edouard@1132: return ([(Gen_PyCfile_path, matiec_flags)], Edouard@1132: "", Edouard@1145: True, Edouard@1132: ("runtime_%s.py"%location_str, file(runtimefile_path,"rb"))) Edouard@1132: