303 contentheader_obj.setscaling(contentheader["scaling"]) |
301 contentheader_obj.setscaling(contentheader["scaling"]) |
304 else: |
302 else: |
305 setattr(contentheader_obj, attr, value) |
303 setattr(contentheader_obj, attr, value) |
306 setattr(cls, "setcontentHeader", setcontentHeader) |
304 setattr(cls, "setcontentHeader", setcontentHeader) |
307 |
305 |
308 def gettypeElement(self, element_type, name=None): |
306 def gettypeElement(self, element_type, name): |
309 filter = "[@name='%s']" % name if name is not None else "" |
307 elements = self.xpath( |
310 elements = self.xpath("ppx:types/ppx:%(element_type)ss/ppx:%(element_type)s%(filter)s" % locals(), |
308 "ppx:types/ppx:%(element_type)ss/ppx:%(element_type)s[@name='%(name)s']" % locals(), |
311 namespaces=PLCOpenParser.NSMAP) |
309 namespaces=PLCOpenParser.NSMAP) |
312 if name is None: |
310 if name is None: |
313 return elements |
311 return elements |
314 elif len(elements) == 1: |
312 elif len(elements) == 1: |
315 return elements[0] |
313 return elements[0] |
316 return None |
314 return None |
317 setattr(cls, "gettypeElement", gettypeElement) |
315 setattr(cls, "gettypeElement", gettypeElement) |
318 |
316 |
319 def getdataTypes(self): |
317 def getdataTypes(self, exclude=None): |
320 return self.getdataType() |
318 return self.xpath( |
|
319 "ppx:types/ppx:dataTypes/ppx:dataType%s" % |
|
320 ("[@name!='%s']" % exclude if exclude is not None else ""), |
|
321 namespaces=PLCOpenParser.NSMAP) |
321 setattr(cls, "getdataTypes", getdataTypes) |
322 setattr(cls, "getdataTypes", getdataTypes) |
322 |
323 |
323 def getdataType(self, name=None): |
324 def getdataType(self, name): |
324 return self.gettypeElement("dataType", name) |
325 return self.gettypeElement("dataType", name) |
325 setattr(cls, "getdataType", getdataType) |
326 setattr(cls, "getdataType", getdataType) |
326 |
327 |
327 def appenddataType(self, name): |
328 def appenddataType(self, name): |
328 if self.getdataType(name) is not None: |
329 if self.getdataType(name) is not None: |
334 self.types.insertdataTypeElement(index, datatype) |
335 self.types.insertdataTypeElement(index, datatype) |
335 setattr(cls, "insertdataType", insertdataType) |
336 setattr(cls, "insertdataType", insertdataType) |
336 |
337 |
337 def removedataType(self, name): |
338 def removedataType(self, name): |
338 self.types.removedataTypeElement(name) |
339 self.types.removedataTypeElement(name) |
339 self.RefreshElementUsingTree() |
|
340 setattr(cls, "removedataType", removedataType) |
340 setattr(cls, "removedataType", removedataType) |
341 |
341 |
342 def getpous(self): |
342 def getpous(self, exclude=None, filter=None): |
343 return self.getpou() |
343 return self.xpath( |
|
344 "ppx:types/ppx:pous/ppx:pou%s%s" % |
|
345 (("[@name!='%s']" % exclude) if exclude is not None else '', |
|
346 ("[%s]" % " or ".join( |
|
347 map(lambda x: "@pouType='%s'" % x, filter))) |
|
348 if filter is not None else ""), |
|
349 namespaces=PLCOpenParser.NSMAP) |
344 setattr(cls, "getpous", getpous) |
350 setattr(cls, "getpous", getpous) |
345 |
351 |
346 def getpou(self, name=None): |
352 def getpou(self, name): |
347 return self.gettypeElement("pou", name) |
353 return self.gettypeElement("pou", name) |
348 setattr(cls, "getpou", getpou) |
354 setattr(cls, "getpou", getpou) |
349 |
355 |
350 def appendpou(self, name, pou_type, body_type): |
356 def appendpou(self, name, pou_type, body_type): |
351 self.types.appendpouElement(name, pou_type, body_type) |
357 self.types.appendpouElement(name, pou_type, body_type) |
352 self.AddCustomBlockType(self.getpou(name)) |
|
353 setattr(cls, "appendpou", appendpou) |
358 setattr(cls, "appendpou", appendpou) |
354 |
359 |
355 def insertpou(self, index, pou): |
360 def insertpou(self, index, pou): |
356 self.types.insertpouElement(index, pou) |
361 self.types.insertpouElement(index, pou) |
357 self.AddCustomBlockType(pou) |
|
358 setattr(cls, "insertpou", insertpou) |
362 setattr(cls, "insertpou", insertpou) |
359 |
363 |
360 def removepou(self, name): |
364 def removepou(self, name): |
361 self.types.removepouElement(name) |
365 self.types.removepouElement(name) |
362 self.RefreshCustomBlockTypes() |
|
363 self.RefreshElementUsingTree() |
|
364 setattr(cls, "removepou", removepou) |
366 setattr(cls, "removepou", removepou) |
365 |
367 |
366 def getconfigurations(self): |
368 def getconfigurations(self): |
367 return self.getconfiguration() |
369 return self.getconfiguration() |
368 setattr(cls, "getconfigurations", getconfigurations) |
370 setattr(cls, "getconfigurations", getconfigurations) |
456 pou.removeVariableByFilter(address_model) |
458 pou.removeVariableByFilter(address_model) |
457 for configuration in self.getconfigurations(): |
459 for configuration in self.getconfigurations(): |
458 configuration.removeVariableByFilter(address_model) |
460 configuration.removeVariableByFilter(address_model) |
459 setattr(cls, "removeVariableByFilter", removeVariableByFilter) |
461 setattr(cls, "removeVariableByFilter", removeVariableByFilter) |
460 |
462 |
461 # Update Block types with user-defined pou added |
|
462 def RefreshCustomBlockTypes(self): |
|
463 # Reset the tree of user-defined pou cross-use |
|
464 self.CustomBlockTypes = OrderedDict() |
|
465 for pou in self.getpous(): |
|
466 self.AddCustomBlockType(pou) |
|
467 setattr(cls, "RefreshCustomBlockTypes", RefreshCustomBlockTypes) |
|
468 |
|
469 def AddCustomBlockType(self, pou): |
|
470 pou_name = pou.getname() |
|
471 pou_type = pou.getpouType() |
|
472 block_infos = {"name" : pou_name, "type" : pou_type, "extensible" : False, |
|
473 "inputs" : [], "outputs" : [], "comment" : pou.getdescription(), |
|
474 "generate" : generate_block, "initialise" : initialise_block} |
|
475 if pou.interface is not None: |
|
476 return_type = pou.interface.getreturnType() |
|
477 if return_type is not None: |
|
478 var_type = return_type.getcontent() |
|
479 var_type_name = var_type.getLocalTag() |
|
480 if var_type_name == "derived": |
|
481 block_infos["outputs"].append(("OUT", var_type.getname(), "none")) |
|
482 elif var_type_name in ["string", "wstring"]: |
|
483 block_infos["outputs"].append(("OUT", var_type_name.upper(), "none")) |
|
484 else: |
|
485 block_infos["outputs"].append(("OUT", var_type_name, "none")) |
|
486 for type, varlist in pou.getvars(): |
|
487 if type == "InOut": |
|
488 for var in varlist.getvariable(): |
|
489 var_type = var.type.getcontent() |
|
490 var_type_name = var_type.getLocalTag() |
|
491 if var_type_name == "derived": |
|
492 block_infos["inputs"].append((var.getname(), var_type.getname(), "none")) |
|
493 block_infos["outputs"].append((var.getname(), var_type.getname(), "none")) |
|
494 elif var_type_name in ["string", "wstring"]: |
|
495 block_infos["inputs"].append((var.getname(), var_type_name.upper(), "none")) |
|
496 block_infos["outputs"].append((var.getname(), var_type_name.upper(), "none")) |
|
497 else: |
|
498 block_infos["inputs"].append((var.getname(), var_type_name, "none")) |
|
499 block_infos["outputs"].append((var.getname(), var_type_name, "none")) |
|
500 elif type == "Input": |
|
501 for var in varlist.getvariable(): |
|
502 var_type = var.type.getcontent() |
|
503 var_type_name = var_type.getLocalTag() |
|
504 if var_type_name == "derived": |
|
505 block_infos["inputs"].append((var.getname(), var_type.getname(), "none")) |
|
506 elif var_type_name in ["string", "wstring"]: |
|
507 block_infos["inputs"].append((var.getname(), var_type_name.upper(), "none")) |
|
508 else: |
|
509 block_infos["inputs"].append((var.getname(), var_type_name, "none")) |
|
510 elif type == "Output": |
|
511 for var in varlist.getvariable(): |
|
512 var_type = var.type.getcontent() |
|
513 var_type_name = var_type.getLocalTag() |
|
514 if var_type_name == "derived": |
|
515 block_infos["outputs"].append((var.getname(), var_type.getname(), "none")) |
|
516 elif var_type_name in ["string", "wstring"]: |
|
517 block_infos["outputs"].append((var.getname(), var_type_name.upper(), "none")) |
|
518 else: |
|
519 block_infos["outputs"].append((var.getname(), var_type_name, "none")) |
|
520 block_infos["usage"] = "\n (%s) => (%s)" % (", ".join(["%s:%s" % (input[1], input[0]) for input in block_infos["inputs"]]), |
|
521 ", ".join(["%s:%s" % (output[1], output[0]) for output in block_infos["outputs"]])) |
|
522 self.CustomBlockTypes[pou_name]=block_infos |
|
523 setattr(cls, "AddCustomBlockType", AddCustomBlockType) |
|
524 |
|
525 def AddElementUsingTreeInstance(self, name, type_infos): |
|
526 typename = type_infos.getname() |
|
527 elements = self.ElementUsingTree.setdefault(typename, set()) |
|
528 elements.add(name) |
|
529 setattr(cls, "AddElementUsingTreeInstance", AddElementUsingTreeInstance) |
|
530 |
|
531 def RefreshElementUsingTree(self): |
|
532 # Reset the tree of user-defined element cross-use |
|
533 self.ElementUsingTree = {} |
|
534 |
|
535 # Analyze each datatype |
|
536 for datatype in self.getdataTypes(): |
|
537 name = datatype.getname() |
|
538 basetype_content = datatype.baseType.getcontent() |
|
539 basetype_content_name = basetype_content.getLocalTag() |
|
540 if basetype_content_name == "derived": |
|
541 self.AddElementUsingTreeInstance(name, basetype_content) |
|
542 elif basetype_content_name in ["subrangeSigned", "subrangeUnsigned", "array"]: |
|
543 base_type = basetype_content.baseType.getcontent() |
|
544 if base_type.getLocalTag() == "derived": |
|
545 self.AddElementUsingTreeInstance(name, base_type) |
|
546 elif basetype_content_name == "struct": |
|
547 for element in basetype_content.getvariable(): |
|
548 type_content = element.type.getcontent() |
|
549 if type_content.getLocalTag() == "derived": |
|
550 self.AddElementUsingTreeInstance(name, type_content) |
|
551 |
|
552 # Analyze each pou |
|
553 for pou in self.getpous(): |
|
554 name = pou.getname() |
|
555 if pou.interface is not None: |
|
556 # Extract variables from every varLists |
|
557 for varlist_type, varlist in pou.getvars(): |
|
558 for var in varlist.getvariable(): |
|
559 vartype_content = var.gettype().getcontent() |
|
560 if vartype_content.getLocalTag() == "derived": |
|
561 self.AddElementUsingTreeInstance(name, vartype_content) |
|
562 |
|
563 setattr(cls, "RefreshElementUsingTree", RefreshElementUsingTree) |
|
564 |
|
565 # Return if pou given by name is used by another pou |
|
566 def ElementIsUsed(self, name): |
|
567 elements = self.ElementUsingTree.get(name, None) |
|
568 return elements is not None |
|
569 setattr(cls, "ElementIsUsed", ElementIsUsed) |
|
570 |
|
571 # Return if pou given by name is directly or undirectly used by the reference pou |
|
572 def ElementIsUsedBy(self, name, reference): |
|
573 elements = self.ElementUsingTree.get(name, set()) |
|
574 # Test if pou is directly used by reference |
|
575 if reference in elements: |
|
576 return True |
|
577 else: |
|
578 # Test if pou is undirectly used by reference, by testing if pous |
|
579 # that directly use pou is directly or undirectly used by reference |
|
580 selffn = self.ElementIsUsedBy |
|
581 for element in elements: |
|
582 if selffn(element, reference): |
|
583 return True |
|
584 return False |
|
585 setattr(cls, "ElementIsUsedBy", ElementIsUsedBy) |
|
586 |
|
587 def GetEnumeratedDataTypeValues(self): |
463 def GetEnumeratedDataTypeValues(self): |
588 return [ |
464 return [ |
589 value.getname() |
465 value.getname() |
590 for value in self.xpath( |
466 for value in self.xpath( |
591 "ppx:types/ppx:dataTypes/ppx:dataType/ppx:baseType/ppx:enum/ppx:values/ppx:value", |
467 "ppx:types/ppx:dataTypes/ppx:dataType/ppx:baseType/ppx:enum/ppx:values/ppx:value", |
592 namespaces=PLCOpenParser.NSMAP)] |
468 namespaces=PLCOpenParser.NSMAP)] |
593 setattr(cls, "GetEnumeratedDataTypeValues", GetEnumeratedDataTypeValues) |
469 setattr(cls, "GetEnumeratedDataTypeValues", GetEnumeratedDataTypeValues) |
594 |
|
595 # Function that returns the block definition associated to the block type given |
|
596 def GetCustomBlockType(self, typename, inputs = None): |
|
597 customblocktype = self.CustomBlockTypes.get(typename,None) |
|
598 if customblocktype is not None: |
|
599 if inputs is not None and inputs != "undefined": |
|
600 customblock_inputs = tuple([var_type for name, var_type, modifier in customblocktype["inputs"]]) |
|
601 if inputs == customblock_inputs: |
|
602 return customblocktype |
|
603 else: |
|
604 return customblocktype |
|
605 return None |
|
606 setattr(cls, "GetCustomBlockType", GetCustomBlockType) |
|
607 |
|
608 # Return Block types checking for recursion |
|
609 def GetCustomBlockTypes(self, exclude = None, onlyfunctions = False): |
|
610 if exclude is not None: |
|
611 return [customblocktype for name,customblocktype in self.CustomBlockTypes.iteritems() |
|
612 if (customblocktype["type"] != "program" |
|
613 and name != exclude |
|
614 and not self.ElementIsUsedBy(exclude, name) |
|
615 and not (onlyfunctions and customblocktype["type"] != "function"))] |
|
616 return [customblocktype for customblocktype in self.CustomBlockTypes.itervalues() |
|
617 if (customblocktype["type"] != "program" |
|
618 and not (onlyfunctions and customblocktype["type"] != "function"))] |
|
619 setattr(cls, "GetCustomBlockTypes", GetCustomBlockTypes) |
|
620 |
|
621 # Return Function Block types checking for recursion |
|
622 def GetCustomFunctionBlockTypes(self, exclude = None): |
|
623 if exclude is not None: |
|
624 return [name for name,customblocktype in self.CustomBlockTypes.iteritems() |
|
625 if (customblocktype["type"] == "functionBlock" |
|
626 and name != exclude |
|
627 and not self.ElementIsUsedBy(exclude, name))] |
|
628 return [name for customblocktype in self.CustomBlockTypes.itervalues() |
|
629 if customblocktype["type"] == "functionBlock"] |
|
630 setattr(cls, "GetCustomFunctionBlockTypes", GetCustomFunctionBlockTypes) |
|
631 |
|
632 # Return Block types checking for recursion |
|
633 def GetCustomBlockResource(self): |
|
634 return [customblocktype["name"] for customblocktype in self.CustomBlockTypes.itervalues() |
|
635 if customblocktype["type"] == "program"] |
|
636 setattr(cls, "GetCustomBlockResource", GetCustomBlockResource) |
|
637 |
|
638 # Return Data Types checking for recursion |
|
639 def GetCustomDataTypes(self, exclude = "", only_locatable = False): |
|
640 customdatatypes = [] |
|
641 for customdatatype in self.getdataTypes(): |
|
642 if not only_locatable or self.IsLocatableType(customdatatype): |
|
643 customdatatype_name = customdatatype.getname() |
|
644 if customdatatype_name != exclude and not self.ElementIsUsedBy(exclude, customdatatype_name): |
|
645 customdatatypes.append({"name": customdatatype_name, "infos": customdatatype}) |
|
646 return customdatatypes |
|
647 setattr(cls, "GetCustomDataTypes", GetCustomDataTypes) |
|
648 |
470 |
649 def Search(self, criteria, parent_infos=[]): |
471 def Search(self, criteria, parent_infos=[]): |
650 result = self.types.Search(criteria, parent_infos) |
472 result = self.types.Search(criteria, parent_infos) |
651 for configuration in self.instances.configurations.getconfiguration(): |
473 for configuration in self.instances.configurations.getconfiguration(): |
652 result.extend(configuration.Search(criteria, parent_infos)) |
474 result.extend(configuration.Search(criteria, parent_infos)) |
1166 for result in TestTextElement(value.getname(), criteria): |
988 for result in TestTextElement(value.getname(), criteria): |
1167 search_result.append((tuple(parent_infos + ["value", i]),) + result) |
989 search_result.append((tuple(parent_infos + ["value", i]),) + result) |
1168 return search_result |
990 return search_result |
1169 setattr(cls, "Search", Search) |
991 setattr(cls, "Search", Search) |
1170 |
992 |
|
993 def _getvariableTypeinfos(variable_type): |
|
994 type_content = variable_type.getcontent() |
|
995 type_content_type = type_content.getLocalTag() |
|
996 if type_content_type == "derived": |
|
997 return type_content.getname() |
|
998 return type_content_type.upper() |
|
999 |
1171 cls = PLCOpenParser.GetElementClass("pou", "pous") |
1000 cls = PLCOpenParser.GetElementClass("pou", "pous") |
1172 if cls: |
1001 if cls: |
|
1002 |
|
1003 def getblockInfos(self): |
|
1004 block_infos = { |
|
1005 "name" : self.getname(), |
|
1006 "type" : self.getpouType(), |
|
1007 "extensible" : False, |
|
1008 "inputs" : [], |
|
1009 "outputs" : [], |
|
1010 "comment" : self.getdescription(), |
|
1011 "generate" : generate_block, |
|
1012 "initialise" : initialise_block} |
|
1013 if self.interface is not None: |
|
1014 return_type = self.interface.getreturnType() |
|
1015 if return_type is not None: |
|
1016 block_infos["outputs"].append( |
|
1017 ("OUT", _getvariableTypeinfos(return_type), "none")) |
|
1018 for var in self.xpath( |
|
1019 "ppx:interface/*[self::ppx:inputVars or self::ppx:inOutVars]/ppx:variable", |
|
1020 namespaces=PLCOpenParser.NSMAP): |
|
1021 block_infos["inputs"].append( |
|
1022 (var.getname(), _getvariableTypeinfos(var.type), "none")) |
|
1023 for var in self.xpath( |
|
1024 "ppx:interface/*[self::ppx:outputVars or self::ppx:inOutVars]/ppx:variable", |
|
1025 namespaces=PLCOpenParser.NSMAP): |
|
1026 block_infos["outputs"].append( |
|
1027 (var.getname(), _getvariableTypeinfos(var.type), "none")) |
|
1028 |
|
1029 block_infos["usage"] = ("\n (%s) => (%s)" % |
|
1030 (", ".join(["%s:%s" % (input[1], input[0]) |
|
1031 for input in block_infos["inputs"]]), |
|
1032 ", ".join(["%s:%s" % (output[1], output[0]) |
|
1033 for output in block_infos["outputs"]]))) |
|
1034 return block_infos |
|
1035 setattr(cls, "getblockInfos", getblockInfos) |
1173 |
1036 |
1174 def setdescription(self, description): |
1037 def setdescription(self, description): |
1175 doc = self.getdocumentation() |
1038 doc = self.getdocumentation() |
1176 if doc is None: |
1039 if doc is None: |
1177 doc = PLCOpenParser.CreateElement("documentation", "pou") |
1040 doc = PLCOpenParser.CreateElement("documentation", "pou") |