22 #License along with this library; if not, write to the Free Software |
22 #License along with this library; if not, write to the Free Software |
23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 |
24 |
25 from xml.dom import minidom |
25 from xml.dom import minidom |
26 from types import StringType, UnicodeType, TupleType |
26 from types import StringType, UnicodeType, TupleType |
|
27 from lxml import etree |
27 from copy import deepcopy |
28 from copy import deepcopy |
28 import os,sys,re |
29 import os,sys,re |
29 import datetime |
30 import datetime |
30 from time import localtime |
31 from time import localtime |
31 |
32 |
95 _("Configurations"), _("Resources"), _("Properties")] |
96 _("Configurations"), _("Resources"), _("Properties")] |
96 UNEDITABLE_NAMES = GetUneditableNames() |
97 UNEDITABLE_NAMES = GetUneditableNames() |
97 [USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS, |
98 [USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS, |
98 DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS, |
99 DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS, |
99 RESOURCES, PROPERTIES] = UNEDITABLE_NAMES |
100 RESOURCES, PROPERTIES] = UNEDITABLE_NAMES |
|
101 |
|
102 #------------------------------------------------------------------------------- |
|
103 # Helpers object for generating pou var list |
|
104 #------------------------------------------------------------------------------- |
|
105 |
|
106 def compute_dimensions(el): |
|
107 return [ |
|
108 (dimension.get("lower"), dimension.get("upper")) |
|
109 for dimension in el.findall("dimension")] |
|
110 |
|
111 def extract_param(el): |
|
112 if el.tag == "Type" and el.text is None: |
|
113 array = el.find("array") |
|
114 return ('array', array.text, compute_dimensions(array)) |
|
115 elif el.tag == "Tree": |
|
116 return generate_var_tree(el) |
|
117 elif el.tag == "Edit": |
|
118 return True |
|
119 elif el.text is None: |
|
120 return '' |
|
121 return el.text |
|
122 |
|
123 def generate_var_tree(tree): |
|
124 return ([ |
|
125 (var.get("name"), var.text, generate_var_tree(var)) |
|
126 for var in tree.findall("var")], |
|
127 compute_dimensions(tree)) |
|
128 |
|
129 class AddVariable(etree.XSLTExtension): |
|
130 |
|
131 def __init__(self, variables): |
|
132 etree.XSLTExtension.__init__(self) |
|
133 self.Variables = variables |
|
134 |
|
135 def execute(self, context, self_node, input_node, output_parent): |
|
136 infos = etree.Element('var_infos') |
|
137 self.process_children(context, infos) |
|
138 self.Variables.append( |
|
139 {el.tag.replace("_", " "): extract_param(el) for el in infos}) |
|
140 |
|
141 class VarTree(etree.XSLTExtension): |
|
142 |
|
143 def __init__(self, controller): |
|
144 etree.XSLTExtension.__init__(self) |
|
145 self.Controller = controller |
|
146 |
|
147 def execute(self, context, self_node, input_node, output_parent): |
|
148 typename = input_node.get("name") |
|
149 pou_infos = self.Controller.GetPou(typename) |
|
150 if pou_infos is not None: |
|
151 self.apply_templates(context, pou_infos, output_parent) |
|
152 return |
|
153 |
|
154 datatype_infos = self.Controller.GetDataType(typename) |
|
155 if datatype_infos is not None: |
|
156 self.apply_templates(context, datatype_infos, output_parent) |
|
157 return |
|
158 |
|
159 variables_infos_xslt = etree.parse( |
|
160 os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt")) |
100 |
161 |
101 #------------------------------------------------------------------------------- |
162 #------------------------------------------------------------------------------- |
102 # Undo Buffer for PLCOpenEditor |
163 # Undo Buffer for PLCOpenEditor |
103 #------------------------------------------------------------------------------- |
164 #------------------------------------------------------------------------------- |
104 |
165 |
1222 |
1283 |
1223 # Add variable to varList |
1284 # Add variable to varList |
1224 current_varlist.appendvariable(tempvar) |
1285 current_varlist.appendvariable(tempvar) |
1225 return varlist_list |
1286 return varlist_list |
1226 |
1287 |
1227 def GetVariableDictionary(self, varlist, var): |
1288 def GetVariableDictionary(self, object_with_vars): |
1228 ''' |
1289 variables = [] |
1229 convert a PLC variable to the dictionary representation |
|
1230 returned by Get*Vars) |
|
1231 ''' |
|
1232 |
|
1233 tempvar = {"Name": var.getname()} |
|
1234 |
|
1235 vartype_content = var.gettype().getcontent() |
|
1236 vartype_content_type = vartype_content.getLocalTag() |
|
1237 if vartype_content_type == "derived": |
|
1238 tempvar["Type"] = vartype_content.getname() |
|
1239 elif vartype_content_type == "array": |
|
1240 dimensions = [] |
|
1241 for dimension in vartype_content.getdimension(): |
|
1242 dimensions.append((dimension.getlower(), dimension.getupper())) |
|
1243 base_type = vartype_content.baseType.getcontent() |
|
1244 base_type_type = base_type.getLocalTag() |
|
1245 if base_type_type == "derived": |
|
1246 base_type_name = base_type.getname() |
|
1247 else: |
|
1248 base_type_name = base_type_type.upper() |
|
1249 tempvar["Type"] = ("array", base_type_name, dimensions) |
|
1250 else: |
|
1251 tempvar["Type"] = vartype_content_type.upper() |
|
1252 |
1290 |
1253 tempvar["Edit"] = True |
1291 variables_infos_xslt_tree = etree.XSLT( |
|
1292 variables_infos_xslt, extensions = { |
|
1293 ("var_infos_ns", "add_variable"): AddVariable(variables), |
|
1294 ("var_infos_ns", "var_tree"): VarTree(self)}) |
|
1295 variables_infos_xslt_tree(object_with_vars) |
1254 |
1296 |
1255 initial = var.getinitialValue() |
1297 return variables |
1256 if initial is not None: |
1298 |
1257 tempvar["Initial Value"] = initial.getvalue() |
|
1258 else: |
|
1259 tempvar["Initial Value"] = "" |
|
1260 |
|
1261 address = var.getaddress() |
|
1262 if address: |
|
1263 tempvar["Location"] = address |
|
1264 else: |
|
1265 tempvar["Location"] = "" |
|
1266 |
|
1267 if varlist.getconstant(): |
|
1268 tempvar["Option"] = "Constant" |
|
1269 elif varlist.getretain(): |
|
1270 tempvar["Option"] = "Retain" |
|
1271 elif varlist.getnonretain(): |
|
1272 tempvar["Option"] = "Non-Retain" |
|
1273 else: |
|
1274 tempvar["Option"] = "" |
|
1275 |
|
1276 doc = var.getdocumentation() |
|
1277 if doc is not None: |
|
1278 tempvar["Documentation"] = doc.getanyText() |
|
1279 else: |
|
1280 tempvar["Documentation"] = "" |
|
1281 |
|
1282 return tempvar |
|
1283 |
|
1284 # Add a global var to configuration to configuration |
1299 # Add a global var to configuration to configuration |
1285 def AddConfigurationGlobalVar(self, config_name, type, var_name, |
1300 def AddConfigurationGlobalVar(self, config_name, type, var_name, |
1286 location="", description=""): |
1301 location="", description=""): |
1287 if self.Project is not None: |
1302 if self.Project is not None: |
1288 # Found the configuration corresponding to name |
1303 # Found the configuration corresponding to name |
1302 varlist for vartype, varlist |
1317 varlist for vartype, varlist |
1303 in self.ExtractVarLists(vars)]) |
1318 in self.ExtractVarLists(vars)]) |
1304 |
1319 |
1305 # Return the configuration globalvars |
1320 # Return the configuration globalvars |
1306 def GetConfigurationGlobalVars(self, name, debug = False): |
1321 def GetConfigurationGlobalVars(self, name, debug = False): |
1307 vars = [] |
|
1308 project = self.GetProject(debug) |
1322 project = self.GetProject(debug) |
1309 if project is not None: |
1323 if project is not None: |
1310 # Found the configuration corresponding to name |
1324 # Found the configuration corresponding to name |
1311 configuration = project.getconfiguration(name) |
1325 configuration = project.getconfiguration(name) |
1312 if configuration is not None: |
1326 if configuration is not None: |
1313 # Extract variables from every varLists |
1327 # Extract variables defined in configuration |
1314 for varlist in configuration.getglobalVars(): |
1328 return self.GetVariableDictionary(configuration) |
1315 for var in varlist.getvariable(): |
1329 |
1316 tempvar = self.GetVariableDictionary(varlist, var) |
1330 return [] |
1317 tempvar["Class"] = "Global" |
|
1318 vars.append(tempvar) |
|
1319 return vars |
|
1320 |
1331 |
1321 # Return configuration variable names |
1332 # Return configuration variable names |
1322 def GetConfigurationVariableNames(self, config_name = None, debug = False): |
1333 def GetConfigurationVariableNames(self, config_name = None, debug = False): |
1323 variables = [] |
1334 variables = [] |
1324 project = self.GetProject(debug) |
1335 project = self.GetProject(debug) |
1343 varlist for vartype, varlist |
1354 varlist for vartype, varlist |
1344 in self.ExtractVarLists(vars)]) |
1355 in self.ExtractVarLists(vars)]) |
1345 |
1356 |
1346 # Return the resource globalvars |
1357 # Return the resource globalvars |
1347 def GetConfigurationResourceGlobalVars(self, config_name, name, debug = False): |
1358 def GetConfigurationResourceGlobalVars(self, config_name, name, debug = False): |
1348 vars = [] |
|
1349 project = self.GetProject(debug) |
1359 project = self.GetProject(debug) |
1350 if project is not None: |
1360 if project is not None: |
1351 # Found the resource corresponding to name |
1361 # Found the resource corresponding to name |
1352 resource = project.getconfigurationResource(config_name, name) |
1362 resource = project.getconfigurationResource(config_name, name) |
1353 if resource is not None: |
1363 if resource is not None: |
1354 # Extract variables from every varLists |
1364 # Extract variables defined in configuration |
1355 for varlist in resource.getglobalVars(): |
1365 return self.GetVariableDictionary(resource) |
1356 for var in varlist.getvariable(): |
1366 |
1357 tempvar = self.GetVariableDictionary(varlist, var) |
1367 return [] |
1358 tempvar["Class"] = "Global" |
|
1359 vars.append(tempvar) |
|
1360 return vars |
|
1361 |
1368 |
1362 # Return resource variable names |
1369 # Return resource variable names |
1363 def GetConfigurationResourceVariableNames(self, |
1370 def GetConfigurationResourceVariableNames(self, |
1364 config_name = None, resource_name = None, debug = False): |
1371 config_name = None, resource_name = None, debug = False): |
1365 variables = [] |
1372 variables = [] |
1373 [var.getname() for var in reduce( |
1380 [var.getname() for var in reduce( |
1374 lambda x, y: x + y, [varlist.getvariable() |
1381 lambda x, y: x + y, [varlist.getvariable() |
1375 for varlist in resource.globalVars], |
1382 for varlist in resource.globalVars], |
1376 [])]) |
1383 [])]) |
1377 return variables |
1384 return variables |
1378 |
|
1379 # Recursively generate element name tree for a structured variable |
|
1380 def GenerateVarTree(self, typename, debug = False): |
|
1381 project = self.GetProject(debug) |
|
1382 if project is not None: |
|
1383 blocktype = self.GetBlockType(typename, debug = debug) |
|
1384 if blocktype is not None: |
|
1385 tree = [] |
|
1386 en = False |
|
1387 eno = False |
|
1388 for var_name, var_type, var_modifier in blocktype["inputs"] + blocktype["outputs"]: |
|
1389 en |= var_name.upper() == "EN" |
|
1390 eno |= var_name.upper() == "ENO" |
|
1391 tree.append((var_name, var_type, self.GenerateVarTree(var_type, debug))) |
|
1392 if not eno: |
|
1393 tree.insert(0, ("ENO", "BOOL", ([], []))) |
|
1394 if not en: |
|
1395 tree.insert(0, ("EN", "BOOL", ([], []))) |
|
1396 return tree, [] |
|
1397 datatype = self.GetDataType(typename) |
|
1398 if datatype is not None: |
|
1399 tree = [] |
|
1400 basetype_content = datatype.baseType.getcontent() |
|
1401 basetype_content_type = basetype_content.getLocalTag() |
|
1402 if basetype_content_type == "derived": |
|
1403 return self.GenerateVarTree(basetype_content.getname()) |
|
1404 elif basetype_content_type == "array": |
|
1405 dimensions = [] |
|
1406 base_type = basetype_content.baseType.getcontent() |
|
1407 if base_type.getLocalTag() == "derived": |
|
1408 tree = self.GenerateVarTree(base_type.getname()) |
|
1409 if len(tree[1]) == 0: |
|
1410 tree = tree[0] |
|
1411 for dimension in basetype_content.getdimension(): |
|
1412 dimensions.append((dimension.getlower(), dimension.getupper())) |
|
1413 return tree, dimensions |
|
1414 elif basetype_content_type == "struct": |
|
1415 for element in basetype_content.getvariable(): |
|
1416 element_type = element.type.getcontent() |
|
1417 element_type_type = element_type.getLocalTag() |
|
1418 if element_type_type == "derived": |
|
1419 tree.append((element.getname(), element_type.getname(), self.GenerateVarTree(element_type.getname()))) |
|
1420 else: |
|
1421 tree.append((element.getname(), element_type_type, ([], []))) |
|
1422 return tree, [] |
|
1423 return [], [] |
|
1424 |
1385 |
1425 # Return the interface for the given pou |
1386 # Return the interface for the given pou |
1426 def GetPouInterfaceVars(self, pou, debug = False): |
1387 def GetPouInterfaceVars(self, pou, debug = False): |
1427 vars = [] |
1388 interface = pou.interface |
1428 # Verify that the pou has an interface |
1389 # Verify that the pou has an interface |
1429 if pou.interface is not None: |
1390 if interface is not None: |
1430 # Extract variables from every varLists |
1391 # Extract variables defined in interface |
1431 for type, varlist in pou.getvars(): |
1392 return self.GetVariableDictionary(interface) |
1432 for var in varlist.getvariable(): |
1393 return [] |
1433 tempvar = self.GetVariableDictionary(varlist, var) |
|
1434 |
|
1435 tempvar["Class"] = type |
|
1436 tempvar["Tree"] = ([], []) |
|
1437 |
|
1438 vartype_content = var.gettype().getcontent() |
|
1439 if vartype_content.getLocalTag() == "derived": |
|
1440 tempvar["Edit"] = not pou.hasblock(tempvar["Name"]) |
|
1441 tempvar["Tree"] = self.GenerateVarTree(tempvar["Type"], debug) |
|
1442 |
|
1443 vars.append(tempvar) |
|
1444 return vars |
|
1445 |
1394 |
1446 # Replace the Pou interface by the one given |
1395 # Replace the Pou interface by the one given |
1447 def SetPouInterfaceVars(self, name, vars): |
1396 def SetPouInterfaceVars(self, name, vars): |
1448 if self.Project is not None: |
1397 if self.Project is not None: |
1449 # Found the pou corresponding to name and add interface if there isn't one yet |
1398 # Found the pou corresponding to name and add interface if there isn't one yet |
1501 # Verify that the pou has an interface |
1450 # Verify that the pou has an interface |
1502 if pou.interface is not None: |
1451 if pou.interface is not None: |
1503 # Return the return type if there is one |
1452 # Return the return type if there is one |
1504 return_type = pou.interface.getreturnType() |
1453 return_type = pou.interface.getreturnType() |
1505 if return_type is not None: |
1454 if return_type is not None: |
1506 returntype_content = return_type.getcontent() |
1455 return_type_infos_xslt_tree = etree.XSLT( |
1507 returntype_content_type = returntype_content.getLocalTag() |
1456 variables_infos_xslt, extensions = { |
1508 if returntype_content_type == "derived": |
1457 ("var_infos_ns", "var_tree"): VarTree(self)}) |
1509 return returntype_content.getname() |
1458 return [extract_param(el) |
1510 else: |
1459 for el in return_type_infos_xslt_tree(return_type).getroot()] |
1511 return returntype_content_type.upper() |
1460 |
1512 return None |
1461 return [None, ([], [])] |
1513 |
1462 |
1514 # Function that add a new confnode to the confnode list |
1463 # Function that add a new confnode to the confnode list |
1515 def AddConfNodeTypesList(self, typeslist): |
1464 def AddConfNodeTypesList(self, typeslist): |
1516 self.ConfNodeTypes.extend(typeslist) |
1465 self.ConfNodeTypes.extend(typeslist) |
1517 addedcat = [{"name": _("%s POUs") % confnodetypes["name"], |
1466 addedcat = [{"name": _("%s POUs") % confnodetypes["name"], |
1676 if not only_locatables or self.IsLocatableDataType(datatype, debug)]) |
1625 if not only_locatables or self.IsLocatableDataType(datatype, debug)]) |
1677 if confnodetypes: |
1626 if confnodetypes: |
1678 for category in self.GetConfNodeDataTypes(name, only_locatables): |
1627 for category in self.GetConfNodeDataTypes(name, only_locatables): |
1679 datatypes.extend(category["list"]) |
1628 datatypes.extend(category["list"]) |
1680 return datatypes |
1629 return datatypes |
|
1630 |
|
1631 # Return Data Type Object |
|
1632 def GetPou(self, typename, debug = False): |
|
1633 project = self.GetProject(debug) |
|
1634 if project is not None: |
|
1635 result = project.getpou(typename) |
|
1636 if result is not None: |
|
1637 return result |
|
1638 for confnodetype in self.ConfNodeTypes: |
|
1639 result = confnodetype["types"].getpou(typename) |
|
1640 if result is not None: |
|
1641 return result |
|
1642 return None |
|
1643 |
1681 |
1644 |
1682 # Return Data Type Object |
1645 # Return Data Type Object |
1683 def GetDataType(self, typename, debug = False): |
1646 def GetDataType(self, typename, debug = False): |
1684 project = self.GetProject(debug) |
1647 project = self.GetProject(debug) |
1685 if project is not None: |
1648 if project is not None: |