99 [USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS, |
99 [USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS, |
100 DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS, |
100 DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS, |
101 RESOURCES, PROPERTIES] = UNEDITABLE_NAMES |
101 RESOURCES, PROPERTIES] = UNEDITABLE_NAMES |
102 |
102 |
103 #------------------------------------------------------------------------------- |
103 #------------------------------------------------------------------------------- |
|
104 # Helper object for loading library in xslt stylesheets |
|
105 #------------------------------------------------------------------------------- |
|
106 |
|
107 class LibraryResolver(etree.Resolver): |
|
108 |
|
109 def __init__(self, controller, debug=False): |
|
110 self.Controller = controller |
|
111 self.Debug = debug |
|
112 |
|
113 def resolve(self, url, pubid, context): |
|
114 lib_name = os.path.basename(url) |
|
115 if lib_name in ["project", "stdlib", "extensions"]: |
|
116 lib_el = etree.Element(lib_name) |
|
117 if lib_name == "project": |
|
118 lib_el.append(deepcopy(self.Controller.GetProject(self.Debug))) |
|
119 elif lib_name == "stdlib": |
|
120 for lib in [StdBlockLibrary, AddnlBlockLibrary]: |
|
121 lib_el.append(deepcopy(lib)) |
|
122 else: |
|
123 for ctn in self.Controller.ConfNodeTypes: |
|
124 lib_el.append(deepcopy(ctn["types"])) |
|
125 return self.resolve_string(etree.tostring(lib_el), context) |
|
126 |
|
127 #------------------------------------------------------------------------------- |
|
128 # Helpers functions for translating list of arguments |
|
129 # from xslt to valid arguments |
|
130 #------------------------------------------------------------------------------- |
|
131 |
|
132 _BoolValue = lambda x: x in ["true", "0"] |
|
133 |
|
134 def _translate_args(translations, args): |
|
135 return [translate(arg[0]) if len(arg) > 0 else None |
|
136 for translate, arg in |
|
137 zip(translations, args)] |
|
138 |
|
139 #------------------------------------------------------------------------------- |
104 # Helpers object for generating pou var list |
140 # Helpers object for generating pou var list |
105 #------------------------------------------------------------------------------- |
141 #------------------------------------------------------------------------------- |
106 |
142 |
107 def compute_dimensions(el): |
143 class _VariableInfos(object): |
108 return [ |
144 __slots__ = ["Name", "Class", "Option", "Location", "InitialValue", |
109 (dimension.get("lower"), dimension.get("upper")) |
145 "Edit", "Documentation", "Type", "Tree", "Number"] |
110 for dimension in el.findall("dimension")] |
146 def __init__(self, *args): |
111 |
147 for attr, value in zip(self.__slots__, args): |
112 def extract_param(el): |
148 setattr(self, attr, value if value is not None else "") |
113 if el.tag == "Type" and el.text is None: |
149 def copy(self): |
114 array = el.find("array") |
150 return _VariableInfos(*[getattr(self, attr) for attr in self.__slots__]) |
115 return ('array', array.text, compute_dimensions(array)) |
151 |
116 elif el.tag == "Tree": |
152 class VariablesInfosFactory: |
117 return generate_var_tree(el) |
|
118 elif el.tag == "Edit": |
|
119 return el.text == "True" |
|
120 elif el.text is None: |
|
121 return '' |
|
122 return el.text |
|
123 |
|
124 def generate_var_tree(tree): |
|
125 return ([ |
|
126 (var.get("name"), var.text, generate_var_tree(var)) |
|
127 for var in tree.findall("var")], |
|
128 compute_dimensions(tree)) |
|
129 |
|
130 class AddVariable(etree.XSLTExtension): |
|
131 |
153 |
132 def __init__(self, variables): |
154 def __init__(self, variables): |
133 etree.XSLTExtension.__init__(self) |
|
134 self.Variables = variables |
155 self.Variables = variables |
135 |
156 self.TreeStack = [] |
136 def execute(self, context, self_node, input_node, output_parent): |
157 self.Type = None |
137 infos = etree.Element('var_infos') |
158 self.Dimensions = None |
138 self.process_children(context, infos) |
159 |
139 self.Variables.append( |
160 def SetType(self, context, *args): |
140 {el.tag.replace("_", " "): extract_param(el) for el in infos}) |
161 self.Type = args[0][0] |
141 |
162 |
142 class VarTree(etree.XSLTExtension): |
163 def GetType(self): |
143 |
164 if len(self.Dimensions) > 0: |
144 def __init__(self, controller, debug): |
165 return ("array", self.Type, self.Dimensions) |
145 etree.XSLTExtension.__init__(self) |
166 return self.Type |
146 self.Controller = controller |
167 |
147 self.Debug = debug |
168 def GetTree(self): |
148 |
169 return (self.TreeStack.pop(-1), self.Dimensions) |
149 def execute(self, context, self_node, input_node, output_parent): |
170 |
150 typename = input_node.get("name") |
171 def AddDimension(self, context, *args): |
151 pou_infos = self.Controller.GetPou(typename, self.Debug) |
172 self.Dimensions.append(tuple( |
152 if pou_infos is not None: |
173 _translate_args([str] * 2, args))) |
153 self.apply_templates(context, pou_infos, output_parent) |
174 |
154 return |
175 def AddTree(self, context, *args): |
155 |
176 self.TreeStack.append([]) |
156 datatype_infos = self.Controller.GetDataType(typename, self.Debug) |
177 self.Dimensions = [] |
157 if datatype_infos is not None: |
178 |
158 self.apply_templates(context, datatype_infos, output_parent) |
179 def AddVarToTree(self, context, *args): |
159 return |
180 var = (args[0][0], self.Type, self.GetTree()) |
160 |
181 self.TreeStack[-1].append(var) |
161 class VarIsEdited(etree.XSLTExtension): |
182 |
162 |
183 def AddVariable(self, context, *args): |
163 def __init__(self, controller, debug): |
184 self.Variables.append(_VariableInfos(*(_translate_args( |
164 etree.XSLTExtension.__init__(self) |
185 [str] * 5 + [_BoolValue] + [str], args) + |
165 self.Controller = controller |
186 [self.GetType(), self.GetTree()]))) |
166 self.Debug = debug |
|
167 |
|
168 def execute(self, context, self_node, input_node, output_parent): |
|
169 typename = input_node.get("name") |
|
170 output_parent.text = str( |
|
171 self.Controller.GetPou(typename, self.Debug) is None) |
|
172 |
|
173 variables_infos_xslt = etree.parse( |
|
174 os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt")) |
|
175 |
187 |
176 #------------------------------------------------------------------------------- |
188 #------------------------------------------------------------------------------- |
177 # Helpers object for generating pou variable instance list |
189 # Helpers object for generating pou variable instance list |
178 #------------------------------------------------------------------------------- |
190 #------------------------------------------------------------------------------- |
179 |
191 |
1297 def ExtractVarLists(self, vars): |
1302 def ExtractVarLists(self, vars): |
1298 varlist_list = [] |
1303 varlist_list = [] |
1299 current_varlist = None |
1304 current_varlist = None |
1300 current_type = None |
1305 current_type = None |
1301 for var in vars: |
1306 for var in vars: |
1302 next_type = (var["Class"], |
1307 next_type = (var.Class, |
1303 var["Option"], |
1308 var.Option, |
1304 var["Location"] in ["", None] or |
1309 var.Location in ["", None] or |
1305 # When declaring globals, located |
1310 # When declaring globals, located |
1306 # and not located variables are |
1311 # and not located variables are |
1307 # in the same declaration block |
1312 # in the same declaration block |
1308 var["Class"] == "Global") |
1313 var.Class == "Global") |
1309 if current_type != next_type: |
1314 if current_type != next_type: |
1310 current_type = next_type |
1315 current_type = next_type |
1311 infos = VAR_CLASS_INFOS.get(var["Class"], None) |
1316 infos = VAR_CLASS_INFOS.get(var.Class, None) |
1312 if infos is not None: |
1317 if infos is not None: |
1313 current_varlist = PLCOpenParser.CreateElement(infos[0], "interface") |
1318 current_varlist = PLCOpenParser.CreateElement(infos[0], "interface") |
1314 else: |
1319 else: |
1315 current_varlist = PLCOpenParser.CreateElement("varList") |
1320 current_varlist = PLCOpenParser.CreateElement("varList") |
1316 varlist_list.append((var["Class"], current_varlist)) |
1321 varlist_list.append((var.Class, current_varlist)) |
1317 if var["Option"] == "Constant": |
1322 if var.Option == "Constant": |
1318 current_varlist.setconstant(True) |
1323 current_varlist.setconstant(True) |
1319 elif var["Option"] == "Retain": |
1324 elif var.Option == "Retain": |
1320 current_varlist.setretain(True) |
1325 current_varlist.setretain(True) |
1321 elif var["Option"] == "Non-Retain": |
1326 elif var.Option == "Non-Retain": |
1322 current_varlist.setnonretain(True) |
1327 current_varlist.setnonretain(True) |
1323 # Create variable and change its properties |
1328 # Create variable and change its properties |
1324 tempvar = PLCOpenParser.CreateElement("variable", "varListPlain") |
1329 tempvar = PLCOpenParser.CreateElement("variable", "varListPlain") |
1325 tempvar.setname(var["Name"]) |
1330 tempvar.setname(var.Name) |
1326 |
1331 |
1327 var_type = PLCOpenParser.CreateElement("type", "variable") |
1332 var_type = PLCOpenParser.CreateElement("type", "variable") |
1328 if isinstance(var["Type"], TupleType): |
1333 if isinstance(var.Type, TupleType): |
1329 if var["Type"][0] == "array": |
1334 if var.Type[0] == "array": |
1330 array_type, base_type_name, dimensions = var["Type"] |
1335 array_type, base_type_name, dimensions = var.Type |
1331 array = PLCOpenParser.CreateElement("array", "dataType") |
1336 array = PLCOpenParser.CreateElement("array", "dataType") |
1332 baseType = PLCOpenParser.CreateElement("baseType", "array") |
1337 baseType = PLCOpenParser.CreateElement("baseType", "array") |
1333 array.setbaseType(baseType) |
1338 array.setbaseType(baseType) |
1334 for i, dimension in enumerate(dimensions): |
1339 for i, dimension in enumerate(dimensions): |
1335 dimension_range = PLCOpenParser.CreateElement("dimension", "array") |
1340 dimension_range = PLCOpenParser.CreateElement("dimension", "array") |
1347 else: |
1352 else: |
1348 derived_datatype = PLCOpenParser.CreateElement("derived", "dataType") |
1353 derived_datatype = PLCOpenParser.CreateElement("derived", "dataType") |
1349 derived_datatype.setname(base_type_name) |
1354 derived_datatype.setname(base_type_name) |
1350 baseType.setcontent(derived_datatype) |
1355 baseType.setcontent(derived_datatype) |
1351 var_type.setcontent(array) |
1356 var_type.setcontent(array) |
1352 elif var["Type"] in self.GetBaseTypes(): |
1357 elif var.Type in self.GetBaseTypes(): |
1353 var_type.setcontent(PLCOpenParser.CreateElement( |
1358 var_type.setcontent(PLCOpenParser.CreateElement( |
1354 var["Type"].lower() |
1359 var.Type.lower() |
1355 if var["Type"] in ["STRING", "WSTRING"] |
1360 if var.Type in ["STRING", "WSTRING"] |
1356 else var["Type"], "dataType")) |
1361 else var.Type, "dataType")) |
1357 else: |
1362 else: |
1358 derived_type = PLCOpenParser.CreateElement("derived", "dataType") |
1363 derived_type = PLCOpenParser.CreateElement("derived", "dataType") |
1359 derived_type.setname(var["Type"]) |
1364 derived_type.setname(var.Type) |
1360 var_type.setcontent(derived_type) |
1365 var_type.setcontent(derived_type) |
1361 tempvar.settype(var_type) |
1366 tempvar.settype(var_type) |
1362 |
1367 |
1363 if var["Initial Value"] != "": |
1368 if var.InitialValue != "": |
1364 value = PLCOpenParser.CreateElement("initialValue", "variable") |
1369 value = PLCOpenParser.CreateElement("initialValue", "variable") |
1365 value.setvalue(var["Initial Value"]) |
1370 value.setvalue(var.InitialValue) |
1366 tempvar.setinitialValue(value) |
1371 tempvar.setinitialValue(value) |
1367 if var["Location"] != "": |
1372 if var.Location != "": |
1368 tempvar.setaddress(var["Location"]) |
1373 tempvar.setaddress(var.Location) |
1369 else: |
1374 else: |
1370 tempvar.setaddress(None) |
1375 tempvar.setaddress(None) |
1371 if var['Documentation'] != "": |
1376 if var.Documentation != "": |
1372 ft = PLCOpenParser.CreateElement("documentation", "variable") |
1377 ft = PLCOpenParser.CreateElement("documentation", "variable") |
1373 ft.setanyText(var['Documentation']) |
1378 ft.setanyText(var.Documentation) |
1374 tempvar.setdocumentation(ft) |
1379 tempvar.setdocumentation(ft) |
1375 |
1380 |
1376 # Add variable to varList |
1381 # Add variable to varList |
1377 current_varlist.appendvariable(tempvar) |
1382 current_varlist.appendvariable(tempvar) |
1378 return varlist_list |
1383 return varlist_list |
1379 |
1384 |
1380 def GetVariableDictionary(self, object_with_vars, debug=False): |
1385 def GetVariableDictionary(self, object_with_vars, tree=False, debug=False): |
1381 variables = [] |
1386 variables = [] |
|
1387 factory = VariablesInfosFactory(variables) |
|
1388 |
|
1389 parser = etree.XMLParser() |
|
1390 if tree: |
|
1391 parser.resolvers.add(LibraryResolver(self, debug)) |
1382 |
1392 |
1383 variables_infos_xslt_tree = etree.XSLT( |
1393 variables_infos_xslt_tree = etree.XSLT( |
1384 variables_infos_xslt, extensions = { |
1394 etree.parse( |
1385 ("var_infos_ns", "add_variable"): AddVariable(variables), |
1395 os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt"), |
1386 ("var_infos_ns", "var_tree"): VarTree(self, debug), |
1396 parser), |
1387 ("var_infos_ns", "is_edited"): VarIsEdited(self, debug)}) |
1397 extensions = {("var_infos_ns", name): getattr(factory, name) |
1388 variables_infos_xslt_tree(object_with_vars) |
1398 for name in ["SetType", "AddDimension", "AddTree", |
|
1399 "AddVarToTree", "AddVariable"]}) |
|
1400 variables_infos_xslt_tree(object_with_vars, |
|
1401 tree=etree.XSLT.strparam(str(tree))) |
1389 |
1402 |
1390 return variables |
1403 return variables |
1391 |
1404 |
1392 # Add a global var to configuration to configuration |
1405 # Add a global var to configuration to configuration |
1393 def AddConfigurationGlobalVar(self, config_name, var_type, var_name, |
1406 def AddConfigurationGlobalVar(self, config_name, var_type, var_name, |
1528 def UpdateEditedElementUsedVariable(self, tagname, old_name, new_name): |
1541 def UpdateEditedElementUsedVariable(self, tagname, old_name, new_name): |
1529 pou = self.GetEditedElement(tagname) |
1542 pou = self.GetEditedElement(tagname) |
1530 if pou is not None: |
1543 if pou is not None: |
1531 pou.updateElementName(old_name, new_name) |
1544 pou.updateElementName(old_name, new_name) |
1532 |
1545 |
1533 # Return the return type of the pou given by its name |
|
1534 def GetPouInterfaceReturnTypeByName(self, name): |
|
1535 project = self.GetProject(debug) |
|
1536 if project is not None: |
|
1537 # Found the pou correponding to name and return the return type |
|
1538 pou = project.getpou(name) |
|
1539 if pou is not None: |
|
1540 return self.GetPouInterfaceReturnType(pou) |
|
1541 return False |
|
1542 |
|
1543 # Return the return type of the given pou |
1546 # Return the return type of the given pou |
1544 def GetPouInterfaceReturnType(self, pou): |
1547 def GetPouInterfaceReturnType(self, pou, tree=False, debug=False): |
1545 # Verify that the pou has an interface |
1548 # Verify that the pou has an interface |
1546 if pou.interface is not None: |
1549 if pou.interface is not None: |
1547 # Return the return type if there is one |
1550 # Return the return type if there is one |
1548 return_type = pou.interface.getreturnType() |
1551 return_type = pou.interface.getreturnType() |
1549 if return_type is not None: |
1552 if return_type is not None: |
|
1553 factory = VariablesInfosFactory([]) |
|
1554 |
|
1555 parser = etree.XMLParser() |
|
1556 if tree: |
|
1557 parser.resolvers.add(LibraryResolver(self)) |
|
1558 |
1550 return_type_infos_xslt_tree = etree.XSLT( |
1559 return_type_infos_xslt_tree = etree.XSLT( |
1551 variables_infos_xslt, extensions = { |
1560 etree.parse( |
1552 ("var_infos_ns", "var_tree"): VarTree(self)}) |
1561 os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt"), |
1553 return [extract_param(el) |
1562 parser), |
1554 for el in return_type_infos_xslt_tree(return_type).getroot()] |
1563 extensions = {("var_infos_ns", name): getattr(factory, name) |
1555 |
1564 for name in ["SetType", "AddDimension", |
1556 return [None, ([], [])] |
1565 "AddTree", "AddVarToTree"]}) |
|
1566 return_type_infos_xslt_tree(return_type, |
|
1567 tree=etree.XSLT.strparam(str(tree))) |
|
1568 if tree: |
|
1569 return [factory.GetType(), factory.GetTree()] |
|
1570 return factory.GetType() |
|
1571 |
|
1572 if tree: |
|
1573 return [None, ([], [])] |
|
1574 return None |
1557 |
1575 |
1558 # Function that add a new confnode to the confnode list |
1576 # Function that add a new confnode to the confnode list |
1559 def AddConfNodeTypesList(self, typeslist): |
1577 def AddConfNodeTypesList(self, typeslist): |
1560 self.ConfNodeTypes.extend(typeslist) |
1578 self.ConfNodeTypes.extend(typeslist) |
1561 addedcat = [{"name": _("%s POUs") % confnodetypes["name"], |
1579 addedcat = [{"name": _("%s POUs") % confnodetypes["name"], |
2207 elif words[0] == 'A': |
2225 elif words[0] == 'A': |
2208 return self.GetActionBodyType(words[1], words[2], debug) |
2226 return self.GetActionBodyType(words[1], words[2], debug) |
2209 return None |
2227 return None |
2210 |
2228 |
2211 # Return the edited element variables |
2229 # Return the edited element variables |
2212 def GetEditedElementInterfaceVars(self, tagname, debug = False): |
2230 def GetEditedElementInterfaceVars(self, tagname, tree=False, debug = False): |
2213 words = tagname.split("::") |
2231 words = tagname.split("::") |
2214 if words[0] in ["P","T","A"]: |
2232 if words[0] in ["P","T","A"]: |
2215 project = self.GetProject(debug) |
2233 project = self.GetProject(debug) |
2216 if project is not None: |
2234 if project is not None: |
2217 pou = project.getpou(words[1]) |
2235 pou = project.getpou(words[1]) |
2218 if pou is not None: |
2236 if pou is not None: |
2219 return self.GetPouInterfaceVars(pou, debug) |
2237 return self.GetPouInterfaceVars(pou, tree, debug) |
2220 return [] |
2238 return [] |
2221 |
2239 |
2222 # Return the edited element return type |
2240 # Return the edited element return type |
2223 def GetEditedElementInterfaceReturnType(self, tagname, debug = False): |
2241 def GetEditedElementInterfaceReturnType(self, tagname, tree=False, debug = False): |
2224 words = tagname.split("::") |
2242 words = tagname.split("::") |
2225 if words[0] == "P": |
2243 if words[0] == "P": |
2226 project = self.GetProject(debug) |
2244 project = self.GetProject(debug) |
2227 if project is not None: |
2245 if project is not None: |
2228 pou = self.Project.getpou(words[1]) |
2246 pou = self.Project.getpou(words[1]) |
2229 if pou is not None: |
2247 if pou is not None: |
2230 return self.GetPouInterfaceReturnType(pou) |
2248 return self.GetPouInterfaceReturnType(pou, tree, debug) |
2231 elif words[0] == 'T': |
2249 elif words[0] == 'T': |
2232 return "BOOL" |
2250 return "BOOL" |
2233 return None |
2251 return None |
2234 |
2252 |
2235 # Change the edited element text |
2253 # Change the edited element text |