# HG changeset patch # User Edouard Tisserant # Date 1565697853 -7200 # Node ID c901baa36bb3f41ef5ed5762a1d20a959822fee2 # Parent f94bc35a023e639a6ea8aeda5aebf4d3b6bda173 SVGHMI: added deduction of HMI tree from list of HMI_* instances. diff -r f94bc35a023e -r c901baa36bb3 svghmi/svghmi.py --- a/svghmi/svghmi.py Mon Aug 12 13:09:55 2019 +0200 +++ b/svghmi/svghmi.py Tue Aug 13 14:04:13 2019 +0200 @@ -9,6 +9,8 @@ from __future__ import absolute_import import os import shutil +from itertools import izip +from pprint import pprint, pformat import wx @@ -33,16 +35,100 @@ ScriptDirectory = paths.AbsDir(__file__) +class HMITreeNode(object): + def __init__(self, path, name, nodetype): + self.path = path + self.name = name + self.nodetype = nodetype + if nodetype in ["HMI_LABEL", "HMI_ROOT"]: + self.children = [] + + def pprint(self, indent = 0): + res = ">"*indent + pformat(self.__dict__, indent = indent, depth = 1) + "\n" + if hasattr(self, "children"): + res += "\n".join([child.pprint(indent = indent + 1) + for child in self.children]) + res += "\n" + + return res + + def place_node(self, node): + best_child = None + known_best_match = 0 + for child in self.children: + in_common = 0 + for child_path_item, node_path_item in izip(child.path, node.path): + if child_path_item == node_path_item: + in_common +=1 + else: + break + if in_common > known_best_match: + known_best_match = in_common + best_child = child + if best_child is not None and best_child.nodetype == "HMI_LABEL": + best_child.place_node(node) + else: + self.children.append(node) + + class SVGHMILibrary(POULibrary): def GetLibraryPath(self): return paths.AbsNeighbourFile(__file__, "pous.xml") def Generate_C(self, buildpath, varlist, IECCFLAGS): + """ + PLC Instance Tree: + prog0 + +->v1 HMI_INT + +->v2 HMI_INT + +->fb0 (type mhoo) + | +->va HMI_LABEL + | +->v3 HMI_INT + | +->v4 HMI_INT + | + +->fb1 (type mhoo) + | +->va HMI_LABEL + | +->v3 HMI_INT + | +->v4 HMI_INT + | + +->fb2 + +->v5 HMI_IN + + HMI tree: + hmi0 + +->v1 + +->v2 + +->fb0_va + | +-> v3 + | +-> v4 + | + +->fb1_va + | +-> v3 + | +-> v4 + | + +->v5 + + """ + # Filter known HMI types hmi_types_instances = [v for v in varlist if v["derived"] in HMI_TYPES] - - # TODO deduce HMI tree + # TODO XXX !!! filter intermediate variables added for FBD feedback loop + + hmi_tree_root = HMITreeNode(None, "hmi0", "HMI_ROOT") + + # TODO add always available variables here ? + # - plc status + # - current page + # - ... + + # deduce HMI tree from PLC HMI_* instances + for v in hmi_types_instances: + path = v["IEC_path"].split(".") + new_node = HMITreeNode(path, path[-1], v["derived"]) + hmi_tree_root.place_node(new_node) + + print(hmi_tree_root.pprint()) # TODO generate C code to observe/access HMI tree variables svghmi_c_filepath = paths.AbsNeighbourFile(__file__, "svghmi.c") diff -r f94bc35a023e -r c901baa36bb3 tests/svghmi/plc.xml --- a/tests/svghmi/plc.xml Mon Aug 12 13:09:55 2019 +0200 +++ b/tests/svghmi/plc.xml Tue Aug 13 14:04:13 2019 +0200 @@ -1,7 +1,7 @@ <?xml version='1.0' encoding='utf-8'?> <project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.plcopen.org/xml/tc6_0201"> <fileHeader companyName="Unknown" productName="Unnamed" productVersion="1" creationDateTime="2019-08-06T14:23:42"/> - <contentHeader name="Unnamed" modificationDateTime="2019-08-09T11:20:07"> + <contentHeader name="Unnamed" modificationDateTime="2019-08-13T10:34:09"> <coordinateInfo> <fbd> <scaling x="5" y="5"/> @@ -22,7 +22,12 @@ <localVars> <variable name="LocalVar0"> <type> - <DINT/> + <derived name="HMI_INT"/> + </type> + </variable> + <variable name="Pump0"> + <type> + <derived name="Pump"/> </type> </variable> </localVars> @@ -85,7 +90,93 @@ <connectionPointOut> <relPosition x="60" y="10"/> </connectionPointOut> - <expression>DINT#1</expression> + <expression>1</expression> + </inVariable> + <block localId="4" typeName="Pump" instanceName="Pump0" executionOrderId="0" height="20" width="45"> + <position x="595" y="50"/> + <inputVariables/> + <inOutVariables/> + <outputVariables/> + </block> + </FBD> + </body> + </pou> + <pou name="Pump" pouType="functionBlock"> + <interface> + <localVars> + <variable name="hmi"> + <type> + <derived name="HMI_LABEL"/> + </type> + </variable> + <variable name="Pressure"> + <type> + <derived name="HMI_INT"/> + </type> + </variable> + </localVars> + </interface> + <body> + <FBD> + <inOutVariable localId="1" executionOrderId="0" height="30" width="75" negatedOut="false" negatedIn="false"> + <position x="285" y="105"/> + <connectionPointIn> + <relPosition x="0" y="15"/> + <connection refLocalId="2" formalParameter="OUT"> + <position x="285" y="120"/> + <position x="275" y="120"/> + <position x="275" y="95"/> + <position x="550" y="95"/> + <position x="550" y="135"/> + <position x="540" y="135"/> + </connection> + </connectionPointIn> + <connectionPointOut> + <relPosition x="75" y="15"/> + </connectionPointOut> + <expression>Pressure</expression> + </inOutVariable> + <block localId="2" typeName="ADD" executionOrderId="0" height="60" width="65"> + <position x="475" y="105"/> + <inputVariables> + <variable formalParameter="IN1"> + <connectionPointIn> + <relPosition x="0" y="30"/> + <connection refLocalId="1"> + <position x="475" y="135"/> + <position x="417" y="135"/> + <position x="417" y="120"/> + <position x="360" y="120"/> + </connection> + </connectionPointIn> + </variable> + <variable formalParameter="IN2"> + <connectionPointIn> + <relPosition x="0" y="50"/> + <connection refLocalId="3"> + <position x="475" y="155"/> + <position x="432" y="155"/> + <position x="432" y="150"/> + <position x="410" y="150"/> + </connection> + </connectionPointIn> + </variable> + </inputVariables> + <inOutVariables/> + <outputVariables> + <variable formalParameter="OUT"> + <connectionPointOut> + <relPosition x="65" y="30"/> + </connectionPointOut> + </variable> + </outputVariables> + </block> + <inVariable localId="3" executionOrderId="0" height="25" width="30" negated="false"> + <position x="380" y="140"/> + <connectionPointOut> + <relPosition x="30" y="10"/> + </connectionPointOut> + <expression>23</expression> </inVariable> </FBD> </body>