py_ext/PythonFileCTNMixin.py
branchsvghmi
changeset 2992 d48ad9c3ec91
parent 2991 ddf6144a56cf
child 3063 466c3df67835
equal deleted inserted replaced
2991:ddf6144a56cf 2992:d48ad9c3ec91
    99         variables = self.CodeFileVariables(self.CodeFile)
    99         variables = self.CodeFileVariables(self.CodeFile)
   100         ret = [(variable.getname(),
   100         ret = [(variable.getname(),
   101                 variable.gettype(),
   101                 variable.gettype(),
   102                 variable.getinitial())
   102                 variable.getinitial())
   103                for variable in variables]
   103                for variable in variables]
   104         ret.extend([("On"+variable.getname()+"Change", "python_poll", "")
   104         location_str = "_".join(map(str, self.GetCurrentLocation()))
   105                     for variable in variables
   105         ret.append(("On_"+location_str+"_Change", "python_poll", ""))
   106                     if variable.getonchange()])
       
   107         return ret
   106         return ret
   108 
   107 
   109     def CTNGenerate_C(self, buildpath, locations):
   108     def CTNGenerate_C(self, buildpath, locations):
   110         # location string for that CTN
   109         # location string for that CTN
   111         location_str = "_".join(map(str, self.GetCurrentLocation()))
   110         location_str = "_".join(map(str, self.GetCurrentLocation()))
   112         configname = self.GetCTRoot().GetProjectConfigNames()[0]
   111         configname = self.GetCTRoot().GetProjectConfigNames()[0]
   113 
   112 
   114         def _onchangecode(var):
   113         def _onchangecode(var):
   115             return '"' + var.getonchange() + \
   114             return var.getonchange() + "('" + var.getname() + "')"
   116                 "('" + var.getname() + "')\"" \
       
   117                 if var.getonchange() else '""'
       
   118 
   115 
   119         def _onchange(var):
   116         def _onchange(var):
   120             return repr(var.getonchange()) \
   117             return repr(var.getonchange()) \
   121                 if var.getonchange() else None
   118                 if var.getonchange() else None
   122 
   119 
   133                 "IECtype": self.GetCTRoot().GetBaseType(variable.gettype()),
   130                 "IECtype": self.GetCTRoot().GetBaseType(variable.gettype()),
   134                 "initial": repr(variable.getinitial()),
   131                 "initial": repr(variable.getinitial()),
   135                 "pyextname": pyextname
   132                 "pyextname": pyextname
   136             },
   133             },
   137             self.CodeFile.variables.variable)
   134             self.CodeFile.variables.variable)
       
   135 
       
   136         onchange_var_count = len([None for varinfo in varinfos if varinfo["onchange"]])
       
   137 
   138         # python side PLC global variables access stub
   138         # python side PLC global variables access stub
   139         globalstubs = "\n".join([
   139         globalstubs = "\n".join([
   140             """\
   140             """\
   141 _%(name)s_ctype, _%(name)s_unpack, _%(name)s_pack = \\
   141 _%(name)s_ctype, _%(name)s_unpack, _%(name)s_pack = \\
   142     TypeTranslator["%(IECtype)s"]
   142     TypeTranslator["%(IECtype)s"]
   153     %(desc)s,
   153     %(desc)s,
   154     %(onchange)s,
   154     %(onchange)s,
   155     %(opts)s))
   155     %(opts)s))
   156 """ % varinfo for varinfo in varinfos])
   156 """ % varinfo for varinfo in varinfos])
   157 
   157 
       
   158         on_change_func_body = "\n".join(["""
       
   159     if changes.next():
       
   160         # %(name)s
       
   161         try:
       
   162             %(onchangecode)s
       
   163         except Exception as e:
       
   164             errors.append("%(name)s: "+str(e))
       
   165 """ % varinfo for varinfo in varinfos if varinfo["onchange"]])
   158         # Runtime calls (start, stop, init, and cleanup)
   166         # Runtime calls (start, stop, init, and cleanup)
   159         rtcalls = ""
   167         rtcalls = ""
   160         for section in self.SECTIONS_NAMES:
   168         for section in self.SECTIONS_NAMES:
   161             if section != "globals":
   169             if section != "globals":
   162                 rtcalls += "def _runtime_%s_%s():\n" % (location_str, section)
   170                 rtcalls += "def _runtime_%s_%s():\n" % (location_str, section)
   172         loc_dict = {
   180         loc_dict = {
   173             "pyextname": pyextname,
   181             "pyextname": pyextname,
   174             "globalstubs": globalstubs,
   182             "globalstubs": globalstubs,
   175             "globalsection": globalsection,
   183             "globalsection": globalsection,
   176             "rtcalls": rtcalls,
   184             "rtcalls": rtcalls,
       
   185             "location_str": location_str,
       
   186             "on_change_func_body":on_change_func_body,
       
   187             "onchange_var_count": onchange_var_count
   177         }
   188         }
   178 
   189 
   179         PyFileContent = """\
   190         PyFileContent = """\
   180 #!/usr/bin/env python
   191 #!/usr/bin/env python
   181 # -*- coding: utf-8 -*-
   192 # -*- coding: utf-8 -*-
   183 ##
   194 ##
   184 
   195 
   185 ## Code for PLC global variable access
   196 ## Code for PLC global variable access
   186 from runtime.typemapping import TypeTranslator
   197 from runtime.typemapping import TypeTranslator
   187 import ctypes
   198 import ctypes
       
   199 
       
   200 _PySafeGetChanges_%(pyextname)s = PLCBinary.PySafeGetChanges_%(location_str)s
       
   201 _PySafeGetChanges_%(pyextname)s.restype = ctypes.POINTER(ctypes.c_int * %(onchange_var_count)d)
       
   202 _PySafeGetChanges_%(pyextname)s.argtypes = None
       
   203 
   188 _%(pyextname)sGlobalsDesc = []
   204 _%(pyextname)sGlobalsDesc = []
   189 __ext_name__ = "%(pyextname)s"
   205 __ext_name__ = "%(pyextname)s"
   190 PLCGlobalsDesc.append(( "%(pyextname)s" , _%(pyextname)sGlobalsDesc ))
   206 PLCGlobalsDesc.append(( "%(pyextname)s" , _%(pyextname)sGlobalsDesc ))
   191 %(globalstubs)s
   207 %(globalstubs)s
   192 
   208 
   193 ## User code in "global" scope
   209 ## User code in "global" scope
   194 %(globalsection)s
   210 %(globalsection)s
   195 
   211 
   196 ## Beremiz python runtime calls
   212 ## Beremiz python runtime calls
   197 %(rtcalls)s
   213 %(rtcalls)s
       
   214 
       
   215 def On_%(pyextname)s_Change():
       
   216     changesP = _PySafeGetChanges_%(pyextname)s()
       
   217     if not changesP:
       
   218         raise Exception("PySafeGetChanges returned NULL!")
       
   219     changes = iter(changesP.contents)
       
   220     errors = []
       
   221 %(on_change_func_body)s
       
   222     if len(errors)>0 :
       
   223         raise Exception("Exception in %(pyextname)s OnChange call:\\\\n" + "\\\\n".join(errors))
   198 
   224 
   199 del __ext_name__
   225 del __ext_name__
   200 
   226 
   201 """ % loc_dict
   227 """ % loc_dict
   202 
   228 
   229 }
   255 }
   230 
   256 
   231 """
   257 """
   232 
   258 
   233         vardeconchangefmt = """\
   259         vardeconchangefmt = """\
   234 PYTHON_POLL* __%(name)s_notifier;
   260 int __%(name)s_rbuffer_written = 0;
   235 """
   261 """
   236 
   262 
   237         varretfmt = """\
   263         varretfmt = """\
   238     if(!AtomicCompareExchange(&__%(name)s_wlock, 0, 1)){
   264     if(!AtomicCompareExchange(&__%(name)s_wlock, 0, 1)){
   239         if(__%(name)s_wbuffer_written == 1){
   265         if(__%(name)s_wbuffer_written == 1){
   253         varpubonchangefmt = """\
   279         varpubonchangefmt = """\
   254     if(!AtomicCompareExchange(&__%(name)s_rlock, 0, 1)){
   280     if(!AtomicCompareExchange(&__%(name)s_rlock, 0, 1)){
   255         IEC_%(IECtype)s tmp = __GET_VAR(%(configname)s__%(uppername)s);
   281         IEC_%(IECtype)s tmp = __GET_VAR(%(configname)s__%(uppername)s);
   256         if(NE_%(IECtype)s(1, NULL, __%(name)s_rbuffer, tmp)){
   282         if(NE_%(IECtype)s(1, NULL, __%(name)s_rbuffer, tmp)){
   257             __%(name)s_rbuffer = tmp;
   283             __%(name)s_rbuffer = tmp;
   258             PYTHON_POLL_body__(__%(name)s_notifier);
   284             /* mark variable as changed */
       
   285             __%(name)s_rbuffer_written = 1;
       
   286             some_change = 1;
   259         }
   287         }
   260         AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0);
   288         AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0);
   261     }
   289     }
   262 """
   290 """
   263         varinitonchangefmt = """\
   291 
   264     __%(name)s_notifier = __GET_GLOBAL_ON%(uppername)sCHANGE();
   292         varcollectchangefmt = """\
   265     __SET_VAR(__%(name)s_notifier->,TRIG,,__BOOL_LITERAL(TRUE));
   293     while(AtomicCompareExchange(&__%(name)s_wlock, 0, 1));
   266     __SET_VAR(__%(name)s_notifier->,CODE,,__STRING_LITERAL(%(onchangelen)d,%(onchangecode)s));
   294     pysafe_changes[change_index++] = __%(name)s_rbuffer_written;
       
   295     /* mark variable as unchanged */
       
   296     __%(name)s_rbuffer_written = 0;
       
   297     AtomicCompareExchange((long*)&__%(name)s_wlock, 1, 0);
       
   298 
   267 """
   299 """
   268         vardec = "\n".join([(vardecfmt + vardeconchangefmt
   300         vardec = "\n".join([(vardecfmt + vardeconchangefmt
   269                              if varinfo["onchange"] else vardecfmt) % varinfo
   301                              if varinfo["onchange"] else vardecfmt) % varinfo
   270                             for varinfo in varinfos])
   302                             for varinfo in varinfos])
   271         varret = "\n".join([varretfmt % varinfo for varinfo in varinfos])
   303         varret = "\n".join([varretfmt % varinfo for varinfo in varinfos])
   272         varpub = "\n".join([(varpubonchangefmt if varinfo["onchange"] else
   304         varpub = "\n".join([(varpubonchangefmt if varinfo["onchange"] else
   273                              varpubfmt) % varinfo
   305                              varpubfmt) % varinfo
   274                             for varinfo in varinfos])
   306                             for varinfo in varinfos])
   275         varinit = "\n".join([varinitonchangefmt %
   307         varcollectchange = "\n".join([varcollectchangefmt % varinfo
   276                              dict(onchangelen=len(varinfo["onchangecode"]), **varinfo)
       
   277                              for varinfo in varinfos if varinfo["onchange"]])
   308                              for varinfo in varinfos if varinfo["onchange"]])
       
   309 
       
   310         pysafe_pypoll_code = "On_"+pyextname+"_Change()"
   278 
   311 
   279         loc_dict = {
   312         loc_dict = {
   280             "vardec": vardec,
   313             "vardec": vardec,
   281             "varinit": varinit,
       
   282             "varret": varret,
   314             "varret": varret,
   283             "varpub": varpub,
   315             "varpub": varpub,
   284             "location_str": location_str,
   316             "location_str": location_str,
       
   317             "pysafe_pypoll_code": '"'+pysafe_pypoll_code+'"',
       
   318             "pysafe_pypoll_code_len": len(pysafe_pypoll_code),
       
   319             "varcollectchange": varcollectchange,
       
   320             "onchange_var_count": onchange_var_count
   285         }
   321         }
   286 
   322 
   287         # TODO : use config name obtained from model instead of default
   323         # TODO : use config name obtained from model instead of default
   288         # "config.h". User cannot change config name, but project imported
   324         # "config.h". User cannot change config name, but project imported
   289         # or created in older beremiz vesion could use different name.
   325         # or created in older beremiz vesion could use different name.
   295 #include "iec_types_all.h"
   331 #include "iec_types_all.h"
   296 #include "POUS.h"
   332 #include "POUS.h"
   297 #include "config.h"
   333 #include "config.h"
   298 #include "beremiz.h"
   334 #include "beremiz.h"
   299 
   335 
       
   336 PYTHON_POLL* __%(location_str)s_notifier;
       
   337 
   300 /* User variables reference */
   338 /* User variables reference */
   301 %(vardec)s
   339 %(vardec)s
   302 
   340 
   303 /* Beremiz confnode functions */
   341 /* Beremiz confnode functions */
   304 int __init_%(location_str)s(int argc,char **argv){
   342 int __init_%(location_str)s(int argc,char **argv){
   305 %(varinit)s
   343     __%(location_str)s_notifier = __GET_GLOBAL_ON_%(location_str)s_CHANGE();
       
   344     __SET_VAR(__%(location_str)s_notifier->,TRIG,,__BOOL_LITERAL(TRUE));
       
   345     __SET_VAR(__%(location_str)s_notifier->,CODE,,__STRING_LITERAL(%(pysafe_pypoll_code_len)d,%(pysafe_pypoll_code)s));
       
   346 
   306     return 0;
   347     return 0;
   307 }
   348 }
   308 
   349 
   309 void __cleanup_%(location_str)s(void){
   350 void __cleanup_%(location_str)s(void){
   310 }
   351 }
   312 void __retrieve_%(location_str)s(void){
   353 void __retrieve_%(location_str)s(void){
   313 %(varret)s
   354 %(varret)s
   314 }
   355 }
   315 
   356 
   316 void __publish_%(location_str)s(void){
   357 void __publish_%(location_str)s(void){
       
   358     int some_change = 0;
   317 %(varpub)s
   359 %(varpub)s
   318 }
   360     // call python part if there was at least a change
       
   361     if(some_change){
       
   362         PYTHON_POLL_body__(__%(location_str)s_notifier);
       
   363     }
       
   364 }
       
   365 
       
   366 static int pysafe_changes[%(onchange_var_count)d];
       
   367 void* PySafeGetChanges_%(location_str)s(void){
       
   368     int change_index=0;
       
   369 %(varcollectchange)s
       
   370     return (void*)&pysafe_changes[0];
       
   371 }
       
   372 
   319 """ % loc_dict
   373 """ % loc_dict
   320 
   374 
   321         Gen_PyCfile_path = os.path.join(buildpath, "PyCFile_%s.c" % location_str)
   375         Gen_PyCfile_path = os.path.join(buildpath, "PyCFile_%s.c" % location_str)
   322         pycfile = open(Gen_PyCfile_path, 'w')
   376         pycfile = open(Gen_PyCfile_path, 'w')
   323         pycfile.write(PyCFileContent)
   377         pycfile.write(PyCFileContent)