plcopen/BlockInstanceCollector.py
changeset 1957 2d1cc4f5e4ef
parent 1954 b113d7de4899
child 1959 ce1bfd04b3f6
equal deleted inserted replaced
1956:2b90514edfbf 1957:2d1cc4f5e4ef
       
     1 #!/usr/bin/env python
       
     2 # -*- coding: utf-8 -*-
       
     3 # This file is part of Beremiz.
       
     4 # See COPYING file for copyrights details.
       
     5 
       
     6 from __future__ import absolute_import
       
     7 from plcopen.XSLTModelQuery import XSLTModelQuery, _StringValue, _BoolValue, _translate_args
       
     8 from collections import OrderedDict, namedtuple
       
     9 
       
    10 # -------------------------------------------------------------------------------
       
    11 #           Helpers object for generating pou block instances list
       
    12 # -------------------------------------------------------------------------------
       
    13 
       
    14 
       
    15 _Point = namedtuple("Point", ["x", "y"])
       
    16 
       
    17 _BlockInstanceInfos = namedtuple(
       
    18     "BlockInstanceInfos",
       
    19     ["type", "id", "x", "y", "width", "height", "specific_values", "inputs", "outputs"])
       
    20 
       
    21 _BlockSpecificValues = (
       
    22     namedtuple("BlockSpecificValues",
       
    23                ["name", "execution_order"]),
       
    24     [_StringValue, int])
       
    25 _VariableSpecificValues = (
       
    26     namedtuple("VariableSpecificValues",
       
    27                ["name", "value_type", "execution_order"]),
       
    28     [_StringValue, _StringValue, int])
       
    29 _ConnectionSpecificValues = (
       
    30     namedtuple("ConnectionSpecificValues", ["name"]),
       
    31     [_StringValue])
       
    32 
       
    33 _PowerRailSpecificValues = (
       
    34     namedtuple("PowerRailSpecificValues", ["connectors"]),
       
    35     [int])
       
    36 
       
    37 _LDElementSpecificValues = (
       
    38     namedtuple("LDElementSpecificValues",
       
    39                ["name", "negated", "edge", "storage", "execution_order"]),
       
    40     [_StringValue, _BoolValue, _StringValue, _StringValue, int])
       
    41 
       
    42 _DivergenceSpecificValues = (
       
    43     namedtuple("DivergenceSpecificValues", ["connectors"]),
       
    44     [int])
       
    45 
       
    46 _SpecificValuesTuples = {
       
    47     "comment": (
       
    48         namedtuple("CommentSpecificValues", ["content"]),
       
    49         [_StringValue]),
       
    50     "input": _VariableSpecificValues,
       
    51     "output": _VariableSpecificValues,
       
    52     "inout": _VariableSpecificValues,
       
    53     "connector": _ConnectionSpecificValues,
       
    54     "continuation": _ConnectionSpecificValues,
       
    55     "leftPowerRail": _PowerRailSpecificValues,
       
    56     "rightPowerRail": _PowerRailSpecificValues,
       
    57     "contact": _LDElementSpecificValues,
       
    58     "coil": _LDElementSpecificValues,
       
    59     "step": (
       
    60         namedtuple("StepSpecificValues", ["name", "initial", "action"]),
       
    61         [_StringValue, _BoolValue, lambda x: x]),
       
    62     "transition": (
       
    63         namedtuple("TransitionSpecificValues",
       
    64                    ["priority", "condition_type", "condition", "connection"]),
       
    65         [int, _StringValue, _StringValue, lambda x: x]),
       
    66     "selectionDivergence": _DivergenceSpecificValues,
       
    67     "selectionConvergence": _DivergenceSpecificValues,
       
    68     "simultaneousDivergence": _DivergenceSpecificValues,
       
    69     "simultaneousConvergence": _DivergenceSpecificValues,
       
    70     "jump": (
       
    71         namedtuple("JumpSpecificValues", ["target"]),
       
    72         [_StringValue]),
       
    73     "actionBlock": (
       
    74         namedtuple("ActionBlockSpecificValues", ["actions"]),
       
    75         [lambda x: x]),
       
    76 }
       
    77 
       
    78 _InstanceConnectionInfos = namedtuple(
       
    79     "InstanceConnectionInfos",
       
    80     ["name", "negated", "edge", "position", "links"])
       
    81 
       
    82 _ConnectionLinkInfos = namedtuple(
       
    83     "ConnectionLinkInfos",
       
    84     ["refLocalId", "formalParameter", "points"])
       
    85 
       
    86 
       
    87 class _ActionInfos(object):
       
    88     __slots__ = ["qualifier", "type", "value", "duration", "indicator"]
       
    89 
       
    90     def __init__(self, *args):
       
    91         for attr, value in zip(self.__slots__, args):
       
    92             setattr(self, attr, value if value is not None else "")
       
    93 
       
    94     def copy(self):
       
    95         return _ActionInfos(*[getattr(self, attr) for attr in self.__slots__])
       
    96 
       
    97 
       
    98 class BlockInstanceFactory(object):
       
    99 
       
   100     def __init__(self, block_instances):
       
   101         self.BlockInstances = block_instances
       
   102         self.CurrentInstance = None
       
   103         self.SpecificValues = None
       
   104         self.CurrentConnection = None
       
   105         self.CurrentLink = None
       
   106 
       
   107     def SetSpecificValues(self, context, *args):
       
   108         self.SpecificValues = list(args)
       
   109         self.CurrentInstance = None
       
   110         self.CurrentConnection = None
       
   111         self.CurrentLink = None
       
   112 
       
   113     def AddBlockInstance(self, context, *args):
       
   114         specific_values_tuple, specific_values_translation = \
       
   115             _SpecificValuesTuples.get(args[0][0], _BlockSpecificValues)
       
   116 
       
   117         if args[0][0] == "step" and len(self.SpecificValues) < 3 or \
       
   118            args[0][0] == "transition" and len(self.SpecificValues) < 4:
       
   119             self.SpecificValues.append([None])
       
   120         elif args[0][0] == "actionBlock" and len(self.SpecificValues) < 1:
       
   121             self.SpecificValues.append([[]])
       
   122         specific_values = specific_values_tuple(*_translate_args(
       
   123             specific_values_translation, self.SpecificValues))
       
   124         self.SpecificValues = None
       
   125 
       
   126         self.CurrentInstance = _BlockInstanceInfos(
       
   127             *(_translate_args([_StringValue, int] + [float] * 4, args) +
       
   128               [specific_values, [], []]))
       
   129 
       
   130         self.BlockInstances[self.CurrentInstance.id] = self.CurrentInstance
       
   131 
       
   132     def AddInstanceConnection(self, context, *args):
       
   133         connection_args = _translate_args(
       
   134             [_StringValue] * 2 + [_BoolValue, _StringValue] + [float] * 2, args)
       
   135 
       
   136         self.CurrentConnection = _InstanceConnectionInfos(
       
   137             *(connection_args[1:4] + [
       
   138                 _Point(*connection_args[4:6]), []]))
       
   139 
       
   140         if self.CurrentInstance is not None:
       
   141             if connection_args[0] == "input":
       
   142                 self.CurrentInstance.inputs.append(self.CurrentConnection)
       
   143             else:
       
   144                 self.CurrentInstance.outputs.append(self.CurrentConnection)
       
   145         else:
       
   146             self.SpecificValues.append([self.CurrentConnection])
       
   147 
       
   148     def AddConnectionLink(self, context, *args):
       
   149         self.CurrentLink = _ConnectionLinkInfos(
       
   150             *(_translate_args([int, _StringValue], args) + [[]]))
       
   151         self.CurrentConnection.links.append(self.CurrentLink)
       
   152 
       
   153     def AddLinkPoint(self, context, *args):
       
   154         self.CurrentLink.points.append(_Point(
       
   155             *_translate_args([float] * 2, args)))
       
   156 
       
   157     def AddAction(self, context, *args):
       
   158         if len(self.SpecificValues) == 0:
       
   159             self.SpecificValues.append([[]])
       
   160         translated_args = _translate_args([_StringValue] * 5, args)
       
   161         self.SpecificValues[0][0].append(_ActionInfos(*translated_args))
       
   162 
       
   163 
       
   164 class BlockInstanceCollector(XSLTModelQuery):
       
   165     """ object for collecting instances path list"""
       
   166     def __init__(self, controller):
       
   167         XSLTModelQuery.__init__(self,
       
   168                                 controller,
       
   169                                 "pou_block_instances.xslt",
       
   170                                 [(name, self.FactoryCaller(name))
       
   171                                  for name in ["AddBlockInstance",
       
   172                                               "SetSpecificValues",
       
   173                                               "AddInstanceConnection",
       
   174                                               "AddConnectionLink",
       
   175                                               "AddLinkPoint",
       
   176                                               "AddAction"]])
       
   177 
       
   178     def FactoryCaller(self, funcname):
       
   179         def CallFactory(*args):
       
   180             return getattr(self.factory, funcname)(*args)
       
   181         return CallFactory
       
   182 
       
   183     def Collect(self, root, debug):
       
   184         element_instances = OrderedDict()
       
   185         self.factory = BlockInstanceFactory(element_instances)
       
   186         self._process_xslt(root, debug)
       
   187         self.factory = None
       
   188         return element_instances