|
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 |