# HG changeset patch # User Edouard Tisserant # Date 1368605629 -32400 # Node ID 21475ee0e688cac3dbcb4305d6e57daecc612d1b # Parent 59818c488ead96dce7f72158fe6bd11a26afe5bf Added stub code and declarations for bidirectional access to PLC globals from python code (untested) diff -r 59818c488ead -r 21475ee0e688 py_ext/PythonFileCTNMixin.py --- a/py_ext/PythonFileCTNMixin.py Wed May 15 08:20:17 2013 +0200 +++ b/py_ext/PythonFileCTNMixin.py Wed May 15 17:13:49 2013 +0900 @@ -55,21 +55,28 @@ 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] - variables_str = "" - for variable in self.CodeFile.variables.variable: - global_name = "%s_%s" % (config.upper(), variable.getname().upper()) - variables_str += "# global_var:%s python_var:%s type:%s initial:%s\n" % ( - global_name, - variable.getname(), - variable.gettype(), - str(variable.getinitial())) + # location string for that CTN + location_str = "_".join(map(lambda x:str(x), + self.GetCurrentLocation())) + configname = self.GetCTRoot().GetProjectConfigNames()[0] + + + # 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 = _%(name)s_ctype +_PySafeGetPLCGlob_%(name)s.argtypes = [] +_PySafeSetPLCGlob_%(name)s = PLCBinary.__SafeSetPLCGlob_%(name)s +_PySafeSetPLCGlob_%(name)s.restype = None +_PySafeSetPLCGlob_%(name)s.argtypes = [ctypes.POINTER(_%(name)s_ctype)] +""" % { "name": variable.getname(), + "configname": configname.upper(), + "uppername": variable.getname().upper(), + "IECtype": variable.gettype(), + "initial" : str(variable.getinitial())} + for variable in self.CodeFile.variables.variable]) # Runtime calls (start, stop, init, and cleanup) rtcalls = "" @@ -82,76 +89,117 @@ sectiontext.strip().replace('\n', '\n ')+"\n" else: rtcalls += " pass\n\n" - - text = """\ + + globalsection = self.GetSection("globals") + + PyFileContent = """\ #!/usr/bin/env python # -*- coding: utf-8 -*- ## Code generated by Beremiz python mixin confnode ## ## Code for PLC global variable access -%s +from targets.typemapping import TypeTranslator +import ctypes +%(globalstubs)s ## User code in "global" scope -%s +%(globalsection)s ## Beremiz python runtime calls -%s - -"""%( # variables - variables_str, - # globals - self.GetSection("globals"), - # Beremiz python runtime functions - rtcalls) - +%(rtcalls)s + +""" % locals() + + # write generated content to python file runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str) runtimefile = open(runtimefile_path, 'w') - runtimefile.write(text.encode('utf-8')) + runtimefile.write(PyFileContent.encode('utf-8')) runtimefile.close() - text = """\ + # C code for safe global variables access + + vardecfmt = """\ +extern __%(IECtype)s_t %(configname)s__%(uppername)s; +%(IECtype)s __%(name)s_rbuffer = %(initial)s; +%(IECtype)s __%(name)s_wbuffer; +long __%(name)s_rlock = 0; +long __%(name)s_wlock = 0; +int __%(name)s_wbuffer_written = 0; +%(IECtype)s __SafeGetPLCGlob_%(name)s(){ + %(IECtype)s res; + while(AtomicCompareExchange(&__%(name)s_rlock, 0, 1)); + res = __%(name)s_rbuffer; + AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0); + return res; +} +__SafeSetPLCGlob_%(name)s(%(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); +} + +""" + varretfmt = """\ + if(!AtomicCompareExchange(&__%(name)s_wlock, 0, 1)){ + if(__%(name)s_wbuffer_written == 1){ + %(configname)s__%(uppername)s.value = __%(name)s_wbuffer; + __%(name)s_wbuffer_written = 0; + } + AtomicCompareExchange((long*)&__%(name)s_wlock, 1, 0); + } +""" + varpubfmt = """\ + if(!AtomicCompareExchange(&__%(name)s_rlock, 0, 1)){ + __%(name)s_rbuffer = %(configname)s__%(uppername)s.value; + AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0); + } +""" + + vardec, varret, varpub = map("\n".join, zip(*[ + map(lambda f : f % varinfo, + (vardecfmt, varretfmt, varpubfmt)) + for varinfo in map(lambda variable : { + "name": variable.getname(), + "configname": configname.upper(), + "uppername": variable.getname().upper(), + "IECtype": "IEC_%s"%variable.gettype(), + "initial" : str(variable.getinitial())}, + self.CodeFile.variables.variable)])) + + PyCFileContent = """\ /* * 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" +#include "beremiz.h" + +/* User variables reference */ +%(vardec)s + +/* Beremiz confnode functions */ +int __init_%(location_str)s(int argc,char **argv){ + return 0; +} + +void __cleanup_%(location_str)s(void){ +} + +void __retrieve_%(location_str)s(void){ +%(varret)s +} + +void __publish_%(location_str)s(void){ +%(varpub)s +} +""" % locals() Gen_PyCfile_path = os.path.join(buildpath, "PyCFile_%s.c"%location_str) pycfile = open(Gen_PyCfile_path,'w') - pycfile.write(text) + pycfile.write(PyCFileContent) pycfile.close() matiec_flags = '"-I%s"'%os.path.abspath( diff -r 59818c488ead -r 21475ee0e688 runtime/PLCObject.py --- a/runtime/PLCObject.py Wed May 15 08:20:17 2013 +0200 +++ b/runtime/PLCObject.py Wed May 15 17:13:49 2013 +0900 @@ -264,6 +264,14 @@ self.python_runtime_vars["_runtime_%s"%methodname] = [] self.python_runtime_vars["PLCObject"] = self self.python_runtime_vars["PLCBinary"] = self.PLClibraryHandle + class PLCSafeGlobals: + def __getattr__(self, name): + r = globals()["_PySafeGetPLCGlob_"+name]() + return globals()["_"+name+"_unpack"](r) + def __setattr__(self, name, value): + v = globals()["_"+name+"_pack"](c_type,value) + globals()["_PySafeSetPLCGlob_"+name](ctypes.byref(v)) + self.python_runtime_vars["PLCGlobals"] = PLCSafeGlobals() try: for filename in os.listdir(self.workingdir): name, ext = os.path.splitext(filename)