Laurent@814: #!/usr/bin/env python
Laurent@814: # -*- coding: utf-8 -*-
Edouard@1957: # This file is part of Beremiz.
andrej@1571: # See COPYING file for copyrights details.
andrej@1850: 
kinsamanka@3750: 
edouard@1959: from collections import OrderedDict, namedtuple
kinsamanka@3751: from . XSLTModelQuery import XSLTModelQuery, _StringValue, _BoolValue, _translate_args
andrej@1832: 
andrej@1782: # -------------------------------------------------------------------------------
Laurent@1338: #           Helpers object for generating pou block instances list
andrej@1782: # -------------------------------------------------------------------------------
Laurent@1338: 
andrej@1749: 
Laurent@1338: _Point = namedtuple("Point", ["x", "y"])
Laurent@1338: 
andrej@1768: _BlockInstanceInfos = namedtuple(
andrej@1768:     "BlockInstanceInfos",
Laurent@1338:     ["type", "id", "x", "y", "width", "height", "specific_values", "inputs", "outputs"])
Laurent@1338: 
Laurent@1338: _BlockSpecificValues = (
Edouard@1411:     namedtuple("BlockSpecificValues",
Laurent@1338:                ["name", "execution_order"]),
Laurent@1378:     [_StringValue, int])
Laurent@1338: _VariableSpecificValues = (
Edouard@1411:     namedtuple("VariableSpecificValues",
Laurent@1338:                ["name", "value_type", "execution_order"]),
Laurent@1378:     [_StringValue, _StringValue, int])
Laurent@1338: _ConnectionSpecificValues = (
Laurent@1338:     namedtuple("ConnectionSpecificValues", ["name"]),
Laurent@1378:     [_StringValue])
Laurent@1338: 
Laurent@1338: _PowerRailSpecificValues = (
Laurent@1338:     namedtuple("PowerRailSpecificValues", ["connectors"]),
Laurent@1338:     [int])
Laurent@1338: 
Laurent@1338: _LDElementSpecificValues = (
Edouard@1411:     namedtuple("LDElementSpecificValues",
Laurent@1338:                ["name", "negated", "edge", "storage", "execution_order"]),
Laurent@1378:     [_StringValue, _BoolValue, _StringValue, _StringValue, int])
Laurent@1338: 
Laurent@1338: _DivergenceSpecificValues = (
Laurent@1338:     namedtuple("DivergenceSpecificValues", ["connectors"]),
Laurent@1338:     [int])
Laurent@1338: 
Laurent@1338: _SpecificValuesTuples = {
Laurent@1338:     "comment": (
Laurent@1338:         namedtuple("CommentSpecificValues", ["content"]),
Laurent@1378:         [_StringValue]),
Laurent@1338:     "input": _VariableSpecificValues,
Laurent@1338:     "output": _VariableSpecificValues,
Laurent@1338:     "inout": _VariableSpecificValues,
Laurent@1338:     "connector": _ConnectionSpecificValues,
Laurent@1338:     "continuation": _ConnectionSpecificValues,
Laurent@1338:     "leftPowerRail": _PowerRailSpecificValues,
Laurent@1338:     "rightPowerRail": _PowerRailSpecificValues,
Laurent@1338:     "contact": _LDElementSpecificValues,
Laurent@1338:     "coil": _LDElementSpecificValues,
Laurent@1338:     "step": (
Laurent@1338:         namedtuple("StepSpecificValues", ["name", "initial", "action"]),
Laurent@1378:         [_StringValue, _BoolValue, lambda x: x]),
Laurent@1338:     "transition": (
Edouard@1411:         namedtuple("TransitionSpecificValues",
Laurent@1338:                    ["priority", "condition_type", "condition", "connection"]),
Laurent@1378:         [int, _StringValue, _StringValue, lambda x: x]),
Laurent@1338:     "selectionDivergence": _DivergenceSpecificValues,
Laurent@1338:     "selectionConvergence": _DivergenceSpecificValues,
Laurent@1338:     "simultaneousDivergence": _DivergenceSpecificValues,
Laurent@1338:     "simultaneousConvergence": _DivergenceSpecificValues,
Laurent@1338:     "jump": (
Laurent@1338:         namedtuple("JumpSpecificValues", ["target"]),
Laurent@1378:         [_StringValue]),
Laurent@1338:     "actionBlock": (
Laurent@1338:         namedtuple("ActionBlockSpecificValues", ["actions"]),
Laurent@1338:         [lambda x: x]),
Laurent@1338: }
Laurent@1338: 
andrej@1768: _InstanceConnectionInfos = namedtuple(
andrej@1768:     "InstanceConnectionInfos",
Laurent@1338:     ["name", "negated", "edge", "position", "links"])
Laurent@1338: 
andrej@1768: _ConnectionLinkInfos = namedtuple(
andrej@1768:     "ConnectionLinkInfos",
Laurent@1338:     ["refLocalId", "formalParameter", "points"])
Laurent@1338: 
andrej@1736: 
Laurent@1341: class _ActionInfos(object):
Laurent@1339:     __slots__ = ["qualifier", "type", "value", "duration", "indicator"]
andrej@1751: 
Laurent@1339:     def __init__(self, *args):
Laurent@1339:         for attr, value in zip(self.__slots__, args):
Laurent@1339:             setattr(self, attr, value if value is not None else "")
andrej@1751: 
Laurent@1339:     def copy(self):
Laurent@1339:         return _ActionInfos(*[getattr(self, attr) for attr in self.__slots__])
Laurent@1338: 
andrej@1736: 
andrej@1831: class BlockInstanceFactory(object):
Edouard@1411: 
Laurent@1338:     def __init__(self, block_instances):
Laurent@1338:         self.BlockInstances = block_instances
Laurent@1338:         self.CurrentInstance = None
edouard@3867:         self.SpecificValues = None
Laurent@1338:         self.CurrentConnection = None
Laurent@1338:         self.CurrentLink = None
Edouard@1411: 
Laurent@1338:     def SetSpecificValues(self, context, *args):
Laurent@1338:         self.SpecificValues = list(args)
Laurent@1338:         self.CurrentInstance = None
Laurent@1338:         self.CurrentConnection = None
Laurent@1338:         self.CurrentLink = None
Edouard@1411: 
Laurent@1338:     def AddBlockInstance(self, context, *args):
Laurent@1338:         specific_values_tuple, specific_values_translation = \
Laurent@1338:             _SpecificValuesTuples.get(args[0][0], _BlockSpecificValues)
Edouard@1411: 
andrej@1774:         if args[0][0] == "step" and len(self.SpecificValues) < 3 or \
andrej@1766:            args[0][0] == "transition" and len(self.SpecificValues) < 4:
Laurent@1338:             self.SpecificValues.append([None])
Laurent@1338:         elif args[0][0] == "actionBlock" and len(self.SpecificValues) < 1:
Laurent@1338:             self.SpecificValues.append([[]])
Laurent@1338:         specific_values = specific_values_tuple(*_translate_args(
Laurent@1338:             specific_values_translation, self.SpecificValues))
Laurent@1338:         self.SpecificValues = None
Edouard@1411: 
Laurent@1338:         self.CurrentInstance = _BlockInstanceInfos(
edouard@3792:             *(_translate_args([_StringValue, int] + [int] * 4, args) +
Laurent@1338:               [specific_values, [], []]))
Edouard@1411: 
Laurent@1338:         self.BlockInstances[self.CurrentInstance.id] = self.CurrentInstance
Edouard@1411: 
Laurent@1338:     def AddInstanceConnection(self, context, *args):
Laurent@1338:         connection_args = _translate_args(
edouard@3792:             [_StringValue] * 2 + [_BoolValue, _StringValue] + [int] * 2, args)
Edouard@1411: 
Laurent@1338:         self.CurrentConnection = _InstanceConnectionInfos(
Laurent@1338:             *(connection_args[1:4] + [
Laurent@1338:                 _Point(*connection_args[4:6]), []]))
Edouard@1411: 
Laurent@1338:         if self.CurrentInstance is not None:
Laurent@1338:             if connection_args[0] == "input":
Laurent@1338:                 self.CurrentInstance.inputs.append(self.CurrentConnection)
Laurent@1338:             else:
Laurent@1338:                 self.CurrentInstance.outputs.append(self.CurrentConnection)
Laurent@1338:         else:
Laurent@1338:             self.SpecificValues.append([self.CurrentConnection])
Edouard@1411: 
Laurent@1338:     def AddConnectionLink(self, context, *args):
Laurent@1338:         self.CurrentLink = _ConnectionLinkInfos(
Laurent@1378:             *(_translate_args([int, _StringValue], args) + [[]]))
Laurent@1338:         self.CurrentConnection.links.append(self.CurrentLink)
Edouard@1411: 
Laurent@1338:     def AddLinkPoint(self, context, *args):
Laurent@1338:         self.CurrentLink.points.append(_Point(
edouard@3792:             *_translate_args([int] * 2, args)))
Edouard@1411: 
Laurent@1338:     def AddAction(self, context, *args):
Laurent@1338:         if len(self.SpecificValues) == 0:
Laurent@1338:             self.SpecificValues.append([[]])
Laurent@1378:         translated_args = _translate_args([_StringValue] * 5, args)
Laurent@1338:         self.SpecificValues[0][0].append(_ActionInfos(*translated_args))
Edouard@1411: 
andrej@1749: 
Edouard@1957: class BlockInstanceCollector(XSLTModelQuery):
Edouard@1957:     """ object for collecting instances path list"""
Edouard@1957:     def __init__(self, controller):
Edouard@1957:         XSLTModelQuery.__init__(self,
Edouard@1957:                                 controller,
Edouard@1957:                                 "pou_block_instances.xslt",
Edouard@1957:                                 [(name, self.FactoryCaller(name))
Edouard@1957:                                  for name in ["AddBlockInstance",
Edouard@1957:                                               "SetSpecificValues",
Edouard@1957:                                               "AddInstanceConnection",
Edouard@1957:                                               "AddConnectionLink",
Edouard@1957:                                               "AddLinkPoint",
Edouard@1957:                                               "AddAction"]])
Laurent@1338: 
Edouard@1957:     def FactoryCaller(self, funcname):
Edouard@1957:         def CallFactory(*args):
Edouard@1957:             return getattr(self.factory, funcname)(*args)
Edouard@1957:         return CallFactory
Laurent@814: 
Edouard@1957:     def Collect(self, root, debug):
Laurent@1338:         element_instances = OrderedDict()
Edouard@1957:         self.factory = BlockInstanceFactory(element_instances)
Edouard@1957:         self._process_xslt(root, debug)
Edouard@1957:         self.factory = None
Laurent@1338:         return element_instances