# HG changeset patch # User Edouard Tisserant # Date 1424302853 -3600 # Node ID 20ff66dcc31d644a10d7cdd54ba1d2e77fa2e1eb # Parent d6b878525ceb6bccb2f29cd7d3b364ed73e197be Added more columns in variable list of extensions' code editors - updating python's PLCGlobals from PLC logic can trigger asynchronous 'OnChange' python call diff -r d6b878525ceb -r 20ff66dcc31d CodeFileTreeNode.py --- a/CodeFileTreeNode.py Tue Feb 17 10:23:57 2015 +0100 +++ b/CodeFileTreeNode.py Thu Feb 19 00:40:53 2015 +0100 @@ -31,6 +31,9 @@ + + + @@ -119,6 +122,9 @@ variable.setname(var["Name"]) variable.settype(var["Type"]) variable.setinitial(var["Initial"]) + variable.setdesc(var["Description"]) + variable.setonchange(var["OnChange"]) + variable.setopts(var["Options"]) self.CodeFile.variables.appendvariable(variable) def GetVariables(self): @@ -126,7 +132,11 @@ for var in self.CodeFileVariables(self.CodeFile): datas.append({"Name" : var.getname(), "Type" : var.gettype(), - "Initial" : var.getinitial()}) + "Initial" : var.getinitial(), + "Description" : var.getdesc(), + "OnChange" : var.getonchange(), + "Options" : var.getopts(), + }) return datas def SetTextParts(self, parts): @@ -157,11 +167,15 @@ return True def CTNGlobalInstances(self): - current_location = self.GetCurrentLocation() - return [(variable.getname(), + variables = self.CodeFileVariables(self.CodeFile) + ret = [(variable.getname(), variable.gettype(), - variable.getinitial()) - for variable in self.CodeFileVariables(self.CodeFile)] + variable.getinitial()) + for variable in variables] + ret.extend([("On"+variable.getname()+"Change", "python_poll", "") + for variable in variables + if variable.getonchange()]) + return ret #------------------------------------------------------------------------------- # Current Buffering Management Functions diff -r d6b878525ceb -r 20ff66dcc31d ProjectController.py --- a/ProjectController.py Tue Feb 17 10:23:57 2015 +0100 +++ b/ProjectController.py Thu Feb 19 00:40:53 2015 +0100 @@ -982,7 +982,7 @@ self.ResetBuildMD5() return False - self.LocationCFilesAndCFLAGS = CTNLocationCFilesAndCFLAGS + LibCFilesAndCFLAGS + self.LocationCFilesAndCFLAGS = LibCFilesAndCFLAGS + CTNLocationCFilesAndCFLAGS self.LDFLAGS = CTNLDFLAGS + LibLDFLAGS ExtraFiles = CTNExtraFiles + LibExtraFiles diff -r d6b878525ceb -r 20ff66dcc31d editors/CodeFileEditor.py --- a/editors/CodeFileEditor.py Tue Feb 17 10:23:57 2015 +0100 +++ b/editors/CodeFileEditor.py Thu Feb 19 00:40:53 2015 +0100 @@ -607,7 +607,7 @@ renderer = None colname = self.GetColLabelValue(col, False) - if colname in ["Name", "Initial"]: + if colname in ["Name", "Initial", "Description", "OnChange", "Options"]: editor = wx.grid.GridCellTextEditor() elif colname == "Class": editor = wx.grid.GridCellChoiceEditor() @@ -658,10 +658,13 @@ self.ParentWindow = window self.Controler = controler - self.VariablesDefaultValue = {"Name" : "", "Type" : DefaultType, "Initial": ""} - self.Table = VariablesTable(self, [], ["#", "Name", "Type", "Initial"]) - self.ColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT] - self.ColSizes = [40, 200, 150, 150] + self.VariablesDefaultValue = {"Name" : "", "Type" : DefaultType, "Initial": "", + "Description":"", "OnChange":"", "Options":""} + self.Table = VariablesTable(self, [], ["#", "Name", "Type", "Initial", + "Description", "OnChange", "Options"]) + self.ColAlignements = [wx.ALIGN_RIGHT] + \ + [wx.ALIGN_LEFT]*(len(self.VariablesDefaultValue)) + self.ColSizes = [20, 150] + [100]*(len(self.VariablesDefaultValue)-1) self.VariablesGrid.SetTable(self.Table) self.VariablesGrid.SetButtons({"Add": self.AddVariableButton, "Delete": self.DeleteVariableButton, diff -r d6b878525ceb -r 20ff66dcc31d py_ext/PythonFileCTNMixin.py --- a/py_ext/PythonFileCTNMixin.py Tue Feb 17 10:23:57 2015 +0100 +++ b/py_ext/PythonFileCTNMixin.py Thu Feb 19 00:40:53 2015 +0100 @@ -65,7 +65,6 @@ getattr(self.CodeFile, section).getanyText() + "\n" + \ self.PostSectionsTexts.get(section,"") - def CTNGenerate_C(self, buildpath, locations): # location string for that CTN location_str = "_".join(map(lambda x:str(x), @@ -73,7 +72,17 @@ configname = self.GetCTRoot().GetProjectConfigNames()[0] pyextname = self.CTNName() - + varinfos = map(lambda variable : { + "name": variable.getname(), + "desc" : repr(variable.getdesc()), + "onchange" : '"'+variable.getonchange()+"('"+variable.getname()+"')\"" \ + if variable.getonchange() else "", + "opts" : repr(variable.getopts()), + "configname" : configname.upper(), + "uppername" : variable.getname().upper(), + "IECtype" : variable.gettype(), + "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 = \\ @@ -84,13 +93,12 @@ _PySafeSetPLCGlob_%(name)s = PLCBinary.__SafeSetPLCGlob_%(name)s _PySafeSetPLCGlob_%(name)s.restype = None _PySafeSetPLCGlob_%(name)s.argtypes = [ctypes.POINTER(_%(name)s_ctype)] -_%(pyextname)sGlobalsDesc.append(("%(name)s","%(IECtype)s")) -""" % { "name": variable.getname(), - "configname": configname.upper(), - "uppername": variable.getname().upper(), - "IECtype": variable.gettype(), - "pyextname":pyextname} - for variable in self.CodeFile.variables.variable]) +_%(pyextname)sGlobalsDesc.append(( + "%(name)s", + "%(IECtype)s", + %(desc)s, + %(opts)s)) +""" % varinfo for varinfo in varinfos]) # Runtime calls (start, stop, init, and cleanup) rtcalls = "" @@ -156,6 +164,11 @@ } """ + + vardeconchangefmt = """\ +PYTHON_POLL* __%(name)s_notifier; +""" + varretfmt = """\ if(!AtomicCompareExchange(&__%(name)s_wlock, 0, 1)){ if(__%(name)s_wbuffer_written == 1){ @@ -167,24 +180,36 @@ """ varpubfmt = """\ if(!AtomicCompareExchange(&__%(name)s_rlock, 0, 1)){ - __%(name)s_rbuffer = %(configname)s__%(uppername)s.value; + __%(name)s_rbuffer = __GET_VAR(%(configname)s__%(uppername)s); AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0); } """ - var_str = 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": variable.gettype()}, - self.CodeFile.variables.variable)])) - if len(var_str) > 0: - vardec, varret, varpub = var_str - else: - vardec = varret = varpub = "" + 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,%(onchange)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 + varpubfmt) % varinfo + for varinfo in varinfos]) + varinit = "\n".join([varinitonchangefmt % dict( + onchangelen = len(varinfo["onchange"]),**varinfo) + for varinfo in varinfos if varinfo["onchange"]]) PyCFileContent = """\ /* @@ -192,6 +217,8 @@ * for safe global variables access */ #include "iec_types_all.h" +#include "POUS.h" +#include "config.h" #include "beremiz.h" /* User variables reference */ @@ -199,6 +226,7 @@ /* Beremiz confnode functions */ int __init_%(location_str)s(int argc,char **argv){ +%(varinit)s return 0; } diff -r d6b878525ceb -r 20ff66dcc31d tests/wamp/beremiz.xml --- a/tests/wamp/beremiz.xml Tue Feb 17 10:23:57 2015 +0100 +++ b/tests/wamp/beremiz.xml Thu Feb 19 00:40:53 2015 +0100 @@ -1,4 +1,4 @@ - + diff -r d6b878525ceb -r 20ff66dcc31d tests/wamp/plc.xml --- a/tests/wamp/plc.xml Tue Feb 17 10:23:57 2015 +0100 +++ b/tests/wamp/plc.xml Thu Feb 19 00:40:53 2015 +0100 @@ -1,7 +1,7 @@ - +